2 * This file is part of the Nice GLib ICE library.
4 * (C) 2006-2009 Collabora Ltd.
5 * Contact: Youness Alaoui
6 * (C) 2006-2009 Nokia Corporation. All rights reserved.
7 * Contact: Kai Vehmanen
9 * The contents of this file are subject to the Mozilla Public License Version
10 * 1.1 (the "License"); you may not use this file except in compliance with
11 * the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS" basis,
15 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 * for the specific language governing rights and limitations under the
19 * The Original Code is the Nice GLib ICE library.
21 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
22 * Corporation. All Rights Reserved.
26 * Youness Alaoui, Collabora Ltd.
27 * Dafydd Harries, Collabora Ltd.
29 * Alternatively, the contents of this file may be used under the terms of the
30 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
31 * case the provisions of LGPL are applicable instead of those above. If you
32 * wish to allow use of your version of this file only under the terms of the
33 * LGPL and not to allow others to use your version of this file under the
34 * MPL, indicate your decision by deleting the provisions above and replace
35 * them with the notice and other provisions required by the LGPL. If you do
36 * not delete the provisions above, a recipient may use your version of this
37 * file under either the MPL or the LGPL.
42 * @brief ICE connectivity checks
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"
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_free (NiceAgent *agent,
75 CandidateCheckPair *pair);
76 static CandidateCheckPair *priv_conn_check_add_for_candidate_pair_matched (
77 NiceAgent *agent, guint stream_id, NiceComponent *component,
78 NiceCandidate *local, NiceCandidate *remote, NiceCheckState initial_state);
79 static gboolean priv_conn_keepalive_tick_agent_locked (NiceAgent *agent,
82 static gint64 priv_timer_remainder (gint64 timer, gint64 now)
87 return (timer - now) / 1000;
91 priv_state_to_gchar (NiceCheckState state)
94 case NICE_CHECK_WAITING:
96 case NICE_CHECK_IN_PROGRESS:
98 case NICE_CHECK_SUCCEEDED:
100 case NICE_CHECK_FAILED:
102 case NICE_CHECK_FROZEN:
104 case NICE_CHECK_DISCOVERED:
107 g_assert_not_reached ();
112 priv_state_to_string (NiceCheckState state)
115 case NICE_CHECK_WAITING:
117 case NICE_CHECK_IN_PROGRESS:
118 return "IN_PROGRESS";
119 case NICE_CHECK_SUCCEEDED:
121 case NICE_CHECK_FAILED:
123 case NICE_CHECK_FROZEN:
125 case NICE_CHECK_DISCOVERED:
128 g_assert_not_reached ();
132 #define SET_PAIR_STATE( a, p, s ) G_STMT_START{\
135 nice_debug ("Agent %p : pair %p state %s (%s)", \
136 a, p, priv_state_to_string (s), G_STRFUNC); \
140 priv_ice_return_to_string (StunUsageIceReturn ice_return)
142 switch (ice_return) {
143 case STUN_USAGE_ICE_RETURN_SUCCESS:
145 case STUN_USAGE_ICE_RETURN_ERROR:
147 case STUN_USAGE_ICE_RETURN_INVALID:
149 case STUN_USAGE_ICE_RETURN_ROLE_CONFLICT:
150 return "role conflict";
151 case STUN_USAGE_ICE_RETURN_INVALID_REQUEST:
152 return "invalid request";
153 case STUN_USAGE_ICE_RETURN_INVALID_METHOD:
154 return "invalid method";
155 case STUN_USAGE_ICE_RETURN_MEMORY_ERROR:
156 return "memory error";
157 case STUN_USAGE_ICE_RETURN_INVALID_ADDRESS:
158 return "invalid address";
159 case STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS:
160 return "no mapped address";
162 g_assert_not_reached ();
167 priv_candidate_type_to_string (NiceCandidateType type)
170 case NICE_CANDIDATE_TYPE_HOST:
172 case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
174 case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
176 case NICE_CANDIDATE_TYPE_RELAYED:
179 g_assert_not_reached ();
184 priv_candidate_transport_to_string (NiceCandidateTransport transport)
187 case NICE_CANDIDATE_TRANSPORT_UDP:
189 case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
191 case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
193 case NICE_CANDIDATE_TRANSPORT_TCP_SO:
196 g_assert_not_reached ();
201 priv_socket_type_to_string (NiceSocketType type)
204 case NICE_SOCKET_TYPE_UDP_BSD:
206 case NICE_SOCKET_TYPE_TCP_BSD:
208 case NICE_SOCKET_TYPE_PSEUDOSSL:
210 case NICE_SOCKET_TYPE_HTTP:
212 case NICE_SOCKET_TYPE_SOCKS5:
214 case NICE_SOCKET_TYPE_UDP_TURN:
216 case NICE_SOCKET_TYPE_UDP_TURN_OVER_TCP:
218 case NICE_SOCKET_TYPE_TCP_ACTIVE:
220 case NICE_SOCKET_TYPE_TCP_PASSIVE:
222 case NICE_SOCKET_TYPE_TCP_SO:
225 g_assert_not_reached ();
230 * Dump the component list of incoming checks
233 print_component_incoming_checks (NiceAgent *agent, NiceStream *stream,
234 NiceComponent *component)
238 for (i = component->incoming_checks.head; i; i = i->next) {
239 IncomingCheck *icheck = i->data;
240 gchar tmpbuf1[INET6_ADDRSTRLEN] = {0};
241 gchar tmpbuf2[INET6_ADDRSTRLEN] = {0};
243 nice_address_to_string (&icheck->local_socket->addr, tmpbuf1);
244 nice_address_to_string (&icheck->from, tmpbuf2);
245 nice_debug ("Agent %p : *** sc=%d/%d : icheck %p : "
246 "sock %s [%s]:%u > [%s]:%u",
247 agent, stream->id, component->id, icheck,
248 priv_socket_type_to_string (icheck->local_socket->type),
249 tmpbuf1, nice_address_get_port (&icheck->local_socket->addr),
250 tmpbuf2, nice_address_get_port (&icheck->from));
255 * Dump the conncheck lists of the agent
258 priv_print_conn_check_lists (NiceAgent *agent, const gchar *where, const gchar *detail)
264 if (!nice_debug_is_verbose ())
267 now = g_get_monotonic_time ();
269 #define PRIORITY_LEN 32
271 nice_debug ("Agent %p : *** conncheck list DUMP (called from %s%s)",
272 agent, where, detail ? detail : "");
273 nice_debug ("Agent %p : *** agent nomination mode %s, %s",
274 agent, agent->nomination_mode == NICE_NOMINATION_MODE_AGGRESSIVE ?
275 "aggressive" : "regular",
276 agent->controlling_mode ? "controlling" : "controlled");
277 for (i = agent->streams; i ; i = i->next) {
278 NiceStream *stream = i->data;
279 for (j = 1; j <= stream->n_components; j++) {
280 NiceComponent *component;
281 for (k = stream->conncheck_list; k ; k = k->next) {
282 CandidateCheckPair *pair = k->data;
283 if (pair->component_id == j) {
284 gchar local_addr[INET6_ADDRSTRLEN];
285 gchar remote_addr[INET6_ADDRSTRLEN];
286 gchar priority[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE];
288 nice_address_to_string (&pair->local->addr, local_addr);
289 nice_address_to_string (&pair->remote->addr, remote_addr);
290 nice_candidate_pair_priority_to_string (pair->priority, priority);
292 nice_debug ("Agent %p : *** sc=%d/%d : pair %p : "
293 "f=%s t=%s:%s sock=%s "
294 "%s:[%s]:%u > %s:[%s]:%u prio=%s/%08x state=%c%s%s%s%s",
295 agent, pair->stream_id, pair->component_id, pair,
297 priv_candidate_type_to_string (pair->local->type),
298 priv_candidate_type_to_string (pair->remote->type),
299 priv_socket_type_to_string (pair->sockptr->type),
300 priv_candidate_transport_to_string (pair->local->transport),
301 local_addr, nice_address_get_port (&pair->local->addr),
302 priv_candidate_transport_to_string (pair->remote->transport),
303 remote_addr, nice_address_get_port (&pair->remote->addr),
304 priority, pair->stun_priority,
305 priv_state_to_gchar (pair->state),
306 pair->valid ? "V" : "",
307 pair->nominated ? "N" : "",
308 pair->use_candidate_on_next_check ? "C" : "",
309 g_slist_find (agent->triggered_check_queue, pair) ? "T" : "");
311 for (l = pair->stun_transactions, m = 0; l; l = l->next, m++) {
312 StunTransaction *stun = l->data;
313 nice_debug ("Agent %p : *** sc=%d/%d : pair %p : "
314 "stun#=%d timer=%d/%d %" G_GINT64_FORMAT "/%dms buf=%p %s",
315 agent, pair->stream_id, pair->component_id, pair, m,
316 stun->timer.retransmissions, stun->timer.max_retransmissions,
317 stun->timer.delay - priv_timer_remainder (stun->next_tick, now),
319 stun->message.buffer,
320 (m == 0 && pair->retransmit) ? "(R)" : "");
324 if (agent_find_component (agent, stream->id, j, NULL, &component))
325 print_component_incoming_checks (agent, stream, component);
330 /* Add the pair to the triggered checks list, if not already present
333 priv_add_pair_to_triggered_check_queue (NiceAgent *agent, CandidateCheckPair *pair)
337 SET_PAIR_STATE (agent, pair, NICE_CHECK_IN_PROGRESS);
338 if (agent->triggered_check_queue == NULL ||
339 g_slist_find (agent->triggered_check_queue, pair) == NULL)
340 agent->triggered_check_queue = g_slist_append (agent->triggered_check_queue, pair);
343 /* Remove the pair from the triggered checks list
346 priv_remove_pair_from_triggered_check_queue (NiceAgent *agent, CandidateCheckPair *pair)
349 agent->triggered_check_queue = g_slist_remove (agent->triggered_check_queue, pair);
352 /* Get the pair from the triggered checks list
354 static CandidateCheckPair *
355 priv_get_pair_from_triggered_check_queue (NiceAgent *agent)
357 CandidateCheckPair *pair = NULL;
359 if (agent->triggered_check_queue) {
360 pair = (CandidateCheckPair *)agent->triggered_check_queue->data;
361 priv_remove_pair_from_triggered_check_queue (agent, pair);
367 * Check if the conncheck list if Active according to
368 * ICE spec, 5.7.4 (Computing States)
370 * note: the ICE spec in unclear about that, but the check list should
371 * be considered active when there is at least a pair in Waiting state
372 * OR a pair in In-Progress state.
375 priv_is_checklist_active (NiceStream *stream)
379 for (i = stream->conncheck_list; i ; i = i->next) {
380 CandidateCheckPair *p = i->data;
381 if (p->state == NICE_CHECK_WAITING || p->state == NICE_CHECK_IN_PROGRESS)
388 * Check if the conncheck list if Frozen according to
389 * ICE spec, 5.7.4 (Computing States)
392 priv_is_checklist_frozen (NiceStream *stream)
396 if (stream->conncheck_list == NULL)
399 for (i = stream->conncheck_list; i ; i = i->next) {
400 CandidateCheckPair *p = i->data;
401 if (p->state != NICE_CHECK_FROZEN)
408 * Check if all components of the stream have
409 * a valid pair (used for ICE spec, 7.1.3.2.3, point 2.)
412 priv_all_components_have_valid_pair (NiceStream *stream)
417 for (i = 1; i <= stream->n_components; i++) {
418 for (j = stream->conncheck_list; j ; j = j->next) {
419 CandidateCheckPair *p = j->data;
420 if (p->component_id == i && p->valid)
430 * Check if the foundation in parameter matches the foundation
431 * of a valid pair in the conncheck list [of stream] (used for ICE spec,
432 * 7.1.3.2.3, point 2.)
435 priv_foundation_matches_a_valid_pair (const gchar *foundation, NiceStream *stream)
439 for (i = stream->conncheck_list; i ; i = i->next) {
440 CandidateCheckPair *p = i->data;
442 strncmp (p->foundation, foundation,
443 NICE_CANDIDATE_PAIR_MAX_FOUNDATION) == 0)
450 * Finds the next connectivity check in WAITING state.
452 static CandidateCheckPair *priv_conn_check_find_next_waiting (GSList *conn_check_list)
456 /* note: list is sorted in priority order to first waiting check has
457 * the highest priority */
458 for (i = conn_check_list; i ; i = i->next) {
459 CandidateCheckPair *p = i->data;
460 if (p->state == NICE_CHECK_WAITING)
468 * Finds the next connectivity check in FROZEN state.
470 static CandidateCheckPair *
471 priv_conn_check_find_next_frozen (GSList *conn_check_list)
475 /* note: list is sorted in priority order to first frozen check has
476 * the highest priority */
477 for (i = conn_check_list; i ; i = i->next) {
478 CandidateCheckPair *p = i->data;
479 if (p->state == NICE_CHECK_FROZEN)
487 * Returns the number of active check lists of the agent
490 priv_number_of_active_check_lists (NiceAgent *agent)
495 for (i = agent->streams; i ; i = i->next)
496 if (priv_is_checklist_active (i->data))
502 * Returns the first stream of the agent having a Frozen
503 * connection check list
506 priv_find_first_frozen_check_list (NiceAgent *agent)
510 for (i = agent->streams; i ; i = i->next) {
511 NiceStream *stream = i->data;
512 if (priv_is_checklist_frozen (stream))
519 * Initiates a new connectivity check for a ICE candidate pair.
521 * @return TRUE on success, FALSE on error
523 static gboolean priv_conn_check_initiate (NiceAgent *agent, CandidateCheckPair *pair)
525 SET_PAIR_STATE (agent, pair, NICE_CHECK_IN_PROGRESS);
526 if (conn_check_send (agent, pair)) {
527 SET_PAIR_STATE (agent, pair, NICE_CHECK_FAILED);
534 * Unfreezes the next connectivity check in the list. Follows the
535 * algorithm (2.) defined in 5.7.4 (Computing States) of the ICE spec
538 * See also sect 7.1.2.2.3 (Updating Pair States), and
539 * priv_conn_check_unfreeze_related().
541 * @return TRUE on success, and FALSE if no frozen candidates were found.
543 static gboolean priv_conn_check_unfreeze_next (NiceAgent *agent, NiceStream *stream)
546 GSList *found_list = NULL;
547 gboolean result = FALSE;
549 priv_print_conn_check_lists (agent, G_STRFUNC, NULL);
551 for (i = stream->conncheck_list; i ; i = i->next) {
552 CandidateCheckPair *p1 = i->data;
553 CandidateCheckPair *pair = NULL;
554 guint lowest_component_id = stream->n_components + 1;
555 guint64 highest_priority = 0;
557 if (g_slist_find_custom (found_list, p1->foundation, (GCompareFunc)strcmp))
559 found_list = g_slist_prepend (found_list, p1->foundation);
561 for (j = stream->conncheck_list; j ; j = j->next) {
562 CandidateCheckPair *p2 = i->data;
563 if (strncmp (p2->foundation, p1->foundation,
564 NICE_CANDIDATE_PAIR_MAX_FOUNDATION) == 0) {
565 if (p2->component_id < lowest_component_id ||
566 (p2->component_id == lowest_component_id &&
567 p2->priority > highest_priority)) {
569 lowest_component_id = p2->component_id;
570 highest_priority = p2->priority;
576 nice_debug ("Agent %p : Pair %p with s/c-id %u/%u (%s) unfrozen.",
577 agent, pair, pair->stream_id, pair->component_id, pair->foundation);
578 SET_PAIR_STATE (agent, pair, NICE_CHECK_WAITING);
582 g_slist_free (found_list);
587 * Unfreezes the next next connectivity check in the list after
588 * check 'success_check' has successfully completed.
590 * See sect 7.1.2.2.3 (Updating Pair States) of ICE spec (ID-19).
592 * @param agent context
593 * @param ok_check a connectivity check that has just completed
595 * @return TRUE on success, and FALSE if no frozen candidates were found.
597 static void priv_conn_check_unfreeze_related (NiceAgent *agent, NiceStream *stream, CandidateCheckPair *ok_check)
602 g_assert_cmpint (ok_check->state, ==, NICE_CHECK_SUCCEEDED);
604 g_assert_cmpuint (stream->id, ==, ok_check->stream_id);
606 priv_print_conn_check_lists (agent, G_STRFUNC, NULL);
608 /* step: perform the step (1) of 'Updating Pair States' */
609 for (i = stream->conncheck_list; i ; i = i->next) {
610 CandidateCheckPair *p = i->data;
612 if (p->stream_id == ok_check->stream_id) {
613 if (p->state == NICE_CHECK_FROZEN &&
614 strncmp (p->foundation, ok_check->foundation,
615 NICE_CANDIDATE_PAIR_MAX_FOUNDATION) == 0) {
616 nice_debug ("Agent %p : Unfreezing check %p (after successful check %p).", agent, p, ok_check);
617 SET_PAIR_STATE (agent, p, NICE_CHECK_WAITING);
622 /* step: perform the step (2) of 'Updating Pair States' */
623 stream = agent_find_stream (agent, ok_check->stream_id);
624 if (priv_all_components_have_valid_pair (stream)) {
625 for (i = agent->streams; i ; i = i->next) {
626 /* the agent examines the check list for each other
627 * media stream in turn
629 NiceStream *s = i->data;
630 if (s->id == ok_check->stream_id)
632 if (priv_is_checklist_active (s)) {
633 /* checklist is Active
635 for (j = s->conncheck_list; j ; j = j->next) {
636 CandidateCheckPair *p = j->data;
637 if (p->state == NICE_CHECK_FROZEN &&
638 priv_foundation_matches_a_valid_pair (p->foundation, stream)) {
639 nice_debug ("Agent %p : Unfreezing check %p from stream %u (after successful check %p).", agent, p, s->id, ok_check);
640 SET_PAIR_STATE (agent, p, NICE_CHECK_WAITING);
643 } else if (priv_is_checklist_frozen (s)) {
644 /* checklist is Frozen
646 gboolean match_found = FALSE;
647 /* check if there is one pair in the check list whose
648 * foundation matches a pair in the valid list under
651 for (j = s->conncheck_list; j ; j = j->next) {
652 CandidateCheckPair *p = j->data;
653 if (priv_foundation_matches_a_valid_pair (p->foundation, stream)) {
655 nice_debug ("Agent %p : Unfreezing check %p from stream %u (after successful check %p).", agent, p, s->id, ok_check);
656 SET_PAIR_STATE (agent, p, NICE_CHECK_WAITING);
661 /* set the pair with the lowest component ID
662 * and highest priority to Waiting
664 priv_conn_check_unfreeze_next (agent, s);
672 * Create a new STUN transaction and add it to the list
673 * of ongoing stun transactions of a pair.
675 * @pair the pair the new stun transaction should be added to.
676 * @return the created stun transaction.
678 static StunTransaction *
679 priv_add_stun_transaction (CandidateCheckPair *pair)
681 StunTransaction *stun = g_slice_new0 (StunTransaction);
682 pair->stun_transactions = g_slist_prepend (pair->stun_transactions, stun);
683 pair->retransmit = TRUE;
688 * Forget a STUN transaction.
690 * @data the stun transaction to be forgotten.
691 * @user_data the component contained the concerned stun agent.
694 priv_forget_stun_transaction (gpointer data, gpointer user_data)
696 StunTransaction *stun = data;
697 NiceComponent *component = user_data;
698 StunTransactionId id;
700 if (stun->message.buffer != NULL) {
701 stun_message_id (&stun->message, id);
702 stun_agent_forget_transaction (&component->stun_agent, id);
707 priv_free_stun_transaction (gpointer data)
709 g_slice_free (StunTransaction, data);
713 * Remove a STUN transaction from a pair, and forget it
714 * from the related component stun agent.
716 * @pair the pair the stun transaction should be removed from.
717 * @stun the stun transaction to be removed.
718 * @component the component containing the stun agent used to
719 * forget the stun transaction.
722 priv_remove_stun_transaction (CandidateCheckPair *pair,
723 StunTransaction *stun, NiceComponent *component)
725 priv_forget_stun_transaction (stun, component);
726 pair->stun_transactions = g_slist_remove (pair->stun_transactions, stun);
727 priv_free_stun_transaction (stun);
731 * Remove all STUN transactions from a pair, and forget them
732 * from the related component stun agent.
734 * @pair the pair the stun list should be cleared.
735 * @component the component containing the stun agent used to
736 * forget the stun transactions.
739 priv_free_all_stun_transactions (CandidateCheckPair *pair,
740 NiceComponent *component)
743 g_slist_foreach (pair->stun_transactions, priv_forget_stun_transaction, component);
744 g_slist_free_full (pair->stun_transactions, priv_free_stun_transaction);
745 pair->stun_transactions = NULL;
749 candidate_check_pair_fail (NiceStream *stream, NiceAgent *agent, CandidateCheckPair *p)
751 NiceComponent *component;
753 component = nice_stream_find_component_by_id (stream, p->component_id);
754 SET_PAIR_STATE (agent, p, NICE_CHECK_FAILED);
755 priv_free_all_stun_transactions (p, component);
759 * Helper function for connectivity check timer callback that
760 * runs through the stream specific part of the state machine.
762 * @param schedule if TRUE, schedule a new check
764 * @return will return FALSE when no more pending timers.
766 static gboolean priv_conn_check_tick_stream (NiceStream *stream, NiceAgent *agent)
768 gboolean keep_timer_going = FALSE;
770 CandidateCheckPair *pair;
771 unsigned int timeout;
774 now = g_get_monotonic_time ();
776 /* step: process ongoing STUN transactions */
777 for (i = stream->conncheck_list; i ; i = i->next) {
778 CandidateCheckPair *p = i->data;
779 gchar tmpbuf1[INET6_ADDRSTRLEN], tmpbuf2[INET6_ADDRSTRLEN];
780 NiceComponent *component;
781 guint index = 0, remaining = 0;
783 if (p->stun_transactions == NULL)
786 if (p->state != NICE_CHECK_IN_PROGRESS)
789 if (!agent_find_component (agent, p->stream_id, p->component_id,
793 j = p->stun_transactions;
795 StunTransaction *stun = j->data;
796 GSList *next = j->next;
798 if (now < stun->next_tick)
801 switch (stun_timer_refresh (&stun->timer)) {
802 case STUN_USAGE_TIMER_RETURN_TIMEOUT:
803 timer_return_timeout:
804 priv_remove_stun_transaction (p, stun, component);
806 case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
807 /* case: retransmission stopped, due to the nomination of
808 * a pair with a higher priority than this in-progress pair,
809 * ICE spec, sect 8.1.2 "Updating States", item 2.2
811 if (!p->retransmit || index > 0)
812 goto timer_return_timeout;
814 /* case: not ready, so schedule a new timeout */
815 timeout = stun_timer_remainder (&stun->timer);
817 nice_debug ("Agent %p :STUN transaction retransmitted on pair %p "
818 "(timer=%d/%d %d/%dms).",
820 stun->timer.retransmissions, stun->timer.max_retransmissions,
821 stun->timer.delay - timeout, stun->timer.delay);
823 agent_socket_send (p->sockptr, &p->remote->addr,
824 stun_message_length (&stun->message),
825 (gchar *)stun->buffer);
827 /* note: convert from milli to microseconds for g_time_val_add() */
828 stun->next_tick = now + timeout * 1000;
831 case STUN_USAGE_TIMER_RETURN_SUCCESS:
832 timeout = stun_timer_remainder (&stun->timer);
833 /* note: convert from milli to microseconds for g_time_val_add() */
834 stun->next_tick = now + timeout * 1000;
838 g_assert_not_reached();
846 keep_timer_going = TRUE;
848 nice_address_to_string (&p->local->addr, tmpbuf1);
849 nice_address_to_string (&p->remote->addr, tmpbuf2);
850 nice_debug ("Agent %p : Retransmissions failed, giving up on pair %p",
852 nice_debug ("Agent %p : Failed pair is [%s]:%u --> [%s]:%u", agent,
853 tmpbuf1, nice_address_get_port (&p->local->addr),
854 tmpbuf2, nice_address_get_port (&p->remote->addr));
855 candidate_check_pair_fail (stream, agent, p);
856 priv_print_conn_check_lists (agent, G_STRFUNC,
857 ", retransmission failed");
859 /* perform a check if a transition state from connected to
860 * ready can be performed. This may happen here, when the last
861 * in-progress pair has expired its retransmission count
862 * in priv_conn_check_tick_stream(), which is a condition to
863 * make the transition connected to ready.
865 conn_check_update_check_list_state_for_ready (agent, stream, component);
869 /* step: perform an ordinary check, ICE spec, 5.8 "Scheduling Checks"
870 * note: This code is executed when the triggered checks list is
871 * empty, and when no STUN message has been sent (pacing constraint)
873 pair = priv_conn_check_find_next_waiting (stream->conncheck_list);
875 priv_print_conn_check_lists (agent, G_STRFUNC,
876 ", got a pair in Waiting state");
877 priv_conn_check_initiate (agent, pair);
881 /* note: this is unclear in the ICE spec, but a check list in Frozen
882 * state (where all pairs are in Frozen state) is not supposed to
883 * change its state by an ordinary check, but only by the success of
884 * checks in other check lists, in priv_conn_check_unfreeze_related().
885 * The underlying idea is to concentrate the checks on a single check
888 if (priv_is_checklist_frozen (stream))
889 return keep_timer_going;
891 /* step: ordinary check continued, if there's no pair in the waiting
892 * state, pick a pair in the frozen state
894 pair = priv_conn_check_find_next_frozen (stream->conncheck_list);
896 priv_print_conn_check_lists (agent, G_STRFUNC,
897 ", got a pair in Frozen state");
898 SET_PAIR_STATE (agent, pair, NICE_CHECK_WAITING);
899 priv_conn_check_initiate (agent, pair);
902 return keep_timer_going;
906 priv_conn_check_tick_stream_nominate (NiceStream *stream, NiceAgent *agent)
908 gboolean keep_timer_going = FALSE;
909 /* s_xxx counters are stream-wide */
910 guint s_inprogress = 0;
911 guint s_succeeded = 0;
912 guint s_discovered = 0;
913 guint s_nominated = 0;
914 guint s_waiting_for_nomination = 0;
918 CandidateCheckPair *other_stream_pair = NULL;
921 /* Search for a nominated pair (or selected to be nominated pair)
922 * from another stream.
924 for (i = agent->streams; i ; i = i->next) {
925 NiceStream *s = i->data;
926 if (s->id == stream->id)
928 for (j = s->conncheck_list; j ; j = j->next) {
929 CandidateCheckPair *p = j->data;
930 if (p->nominated || (p->use_candidate_on_next_check &&
931 p->state != NICE_CHECK_FAILED)) {
932 other_stream_pair = p;
936 if (other_stream_pair)
940 /* we compute some stream-wide counter values */
941 for (i = stream->conncheck_list; i ; i = i->next) {
942 CandidateCheckPair *p = i->data;
943 if (p->state == NICE_CHECK_FROZEN)
945 else if (p->state == NICE_CHECK_IN_PROGRESS)
947 else if (p->state == NICE_CHECK_WAITING)
949 else if (p->state == NICE_CHECK_SUCCEEDED)
951 else if (p->state == NICE_CHECK_DISCOVERED)
956 if ((p->state == NICE_CHECK_SUCCEEDED || p->state == NICE_CHECK_DISCOVERED)
959 else if ((p->state == NICE_CHECK_SUCCEEDED ||
960 p->state == NICE_CHECK_DISCOVERED) && !p->nominated)
961 s_waiting_for_nomination++;
964 /* note: keep the timer going as long as there is work to be done */
966 keep_timer_going = TRUE;
968 if (s_nominated < stream->n_components &&
969 s_waiting_for_nomination) {
970 if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
971 if (agent->nomination_mode == NICE_NOMINATION_MODE_REGULAR &&
972 agent->controlling_mode) {
973 #define NICE_MIN_NUMBER_OF_VALID_PAIRS 2
974 /* ICE 8.1.1.1 Regular nomination
975 * we choose to nominate the valid pair of a component if
976 * - there is no pair left frozen, waiting or in-progress, or
977 * - if there are at least two valid pairs, or
978 * - if there is at least one valid pair of type HOST-HOST
980 * This is the "stopping criterion" described in 8.1.1.1, and is
981 * a "local optimization" between accumulating more valid pairs,
982 * and limiting the time spent waiting for in-progress connections
983 * checks until they finally fail.
985 for (i = stream->components; i; i = i->next) {
986 NiceComponent *component = i->data;
987 CandidateCheckPair *other_component_pair = NULL;
988 CandidateCheckPair *this_component_pair = NULL;
989 NiceCandidate *lcand1 = NULL;
990 NiceCandidate *rcand1 = NULL;
991 NiceCandidate *lcand2, *rcand2;
992 gboolean already_done = FALSE;
993 gboolean found_other_component_pair = FALSE;
994 gboolean found_other_stream_pair = FALSE;
995 gboolean first_nomination = FALSE;
996 gboolean stopping_criterion;
997 /* p_xxx counters are component-wide */
1000 guint p_waiting = 0;
1001 guint p_inprogress = 0;
1002 guint p_host_host_valid = 0;
1004 /* we compute some component-wide counter values */
1005 for (j = stream->conncheck_list; j ; j = j->next) {
1006 CandidateCheckPair *p = j->data;
1007 if (p->component_id == component->id) {
1008 /* verify that the choice of the pair to be nominated
1009 * has not already been done
1011 if (p->use_candidate_on_next_check)
1012 already_done = TRUE;
1013 if (p->state == NICE_CHECK_FROZEN)
1015 else if (p->state == NICE_CHECK_WAITING)
1017 else if (p->state == NICE_CHECK_IN_PROGRESS)
1022 p->local->type == NICE_CANDIDATE_TYPE_HOST &&
1023 p->remote->type == NICE_CANDIDATE_TYPE_HOST)
1024 p_host_host_valid++;
1031 /* Search for a nominated pair (or selected to be nominated pair)
1032 * from another component of this stream.
1034 for (j = stream->conncheck_list; j ; j = j->next) {
1035 CandidateCheckPair *p = j->data;
1036 if (p->component_id == component->id)
1038 if (p->nominated || (p->use_candidate_on_next_check &&
1039 p->state != NICE_CHECK_FAILED)) {
1040 other_component_pair = p;
1045 if (other_stream_pair == NULL && other_component_pair == NULL)
1046 first_nomination = TRUE;
1048 /* We choose a pair to be nominated in the list of valid
1051 * this pair will be the one with the highest priority,
1052 * when we don't have other nominated pairs in other
1053 * components and in other streams
1055 * this pair will be a pair compatible with another nominated
1056 * pair from another component if we found one.
1058 * else this pair will be a pair compatible with another
1059 * nominated pair from another stream if we found one.
1062 for (j = stream->conncheck_list; j ; j = j->next) {
1063 CandidateCheckPair *p = j->data;
1064 /* note: highest priority item selected (list always sorted) */
1065 if (p->component_id == component->id &&
1067 !p->use_candidate_on_next_check &&
1069 /* According a ICE spec, sect 8.1.1.1. "Regular
1070 * Nomination", we enqueue the check that produced this
1071 * valid pair. When this pair has been discovered, we want
1072 * to test its parent pair instead.
1074 if (p->succeeded_pair != NULL) {
1075 g_assert_cmpint (p->state, ==, NICE_CHECK_DISCOVERED);
1076 p = p->succeeded_pair;
1078 g_assert_cmpint (p->state, ==, NICE_CHECK_SUCCEEDED);
1080 if (this_component_pair == NULL)
1081 /* highest priority pair */
1082 this_component_pair = p;
1087 if (first_nomination)
1088 /* use the highest priority pair */
1091 if (other_component_pair) {
1092 lcand2 = other_component_pair->local;
1093 rcand2 = other_component_pair->remote;
1095 if (other_component_pair &&
1096 lcand1->transport == lcand2->transport &&
1097 nice_address_equal_no_port (&lcand1->addr, &lcand2->addr) &&
1098 nice_address_equal_no_port (&rcand1->addr, &rcand2->addr)) {
1099 /* else continue the research with lower priority
1100 * pairs, compatible with a nominated pair of
1103 this_component_pair = p;
1104 found_other_component_pair = TRUE;
1108 if (other_stream_pair) {
1109 lcand2 = other_stream_pair->local;
1110 rcand2 = other_stream_pair->remote;
1112 if (other_stream_pair &&
1113 other_component_pair == NULL &&
1114 lcand1->transport == lcand2->transport &&
1115 nice_address_equal_no_port (&lcand1->addr, &lcand2->addr) &&
1116 nice_address_equal_no_port (&rcand1->addr, &rcand2->addr)) {
1117 /* else continue the research with lower priority
1118 * pairs, compatible with a nominated pair of
1121 this_component_pair = p;
1122 found_other_stream_pair = TRUE;
1128 /* No valid pair for this component */
1129 if (this_component_pair == NULL)
1132 /* The stopping criterion tries to select a set of pairs of
1133 * the same kind (transport/type) for all components of a
1134 * stream, and for all streams, when possible (see last
1137 * When no stream has nominated a pair yet, we apply the
1138 * following criterion :
1139 * - stop if we have a valid host-host pair
1140 * - or stop if we have at least "some* (2 in the current
1141 * implementation) valid pairs, and select the best one
1142 * - or stop if the conncheck cannot evolve more
1144 * Else when the stream has a nominated pair in another
1145 * component we apply this criterion:
1146 * - stop if we have a valid pair of the same kind than this
1147 * other nominated pair.
1148 * - or stop if the conncheck cannot evolve more
1150 * Else when another stream has a nominated pair we apply the
1151 * following criterion:
1152 * - stop if we have a valid pair of the same kind than the
1153 * other nominated pair.
1154 * - or stop if the conncheck cannot evolve more
1156 * When no further evolution of the conncheck is possible, we
1157 * prefer to select the best valid pair we have, *even* if it
1158 * is not compatible with the transport of another stream of
1159 * component. We think it's still a better choice than marking
1160 * this component 'failed'.
1162 stopping_criterion = FALSE;
1163 if (first_nomination && p_host_host_valid > 0) {
1164 stopping_criterion = TRUE;
1165 nice_debug ("Agent %p : stopping criterion: "
1166 "valid host-host pair", agent);
1167 } else if (first_nomination &&
1168 p_valid >= NICE_MIN_NUMBER_OF_VALID_PAIRS) {
1169 stopping_criterion = TRUE;
1170 nice_debug ("Agent %p : stopping criterion: "
1171 "*some* valid pairs", agent);
1172 } else if (found_other_component_pair) {
1173 stopping_criterion = TRUE;
1174 nice_debug ("Agent %p : stopping criterion: "
1175 "matching pair in another component", agent);
1176 } else if (found_other_stream_pair) {
1177 stopping_criterion = TRUE;
1178 nice_debug ("Agent %p : stopping criterion: "
1179 "matching pair in another stream", agent);
1180 } else if (p_waiting == 0 && p_inprogress == 0 && p_frozen == 0) {
1181 stopping_criterion = TRUE;
1182 nice_debug ("Agent %p : stopping criterion: "
1183 "no more pairs to check", agent);
1186 if (!stopping_criterion)
1189 /* when the stopping criterion is reached, we add the
1190 * selected pair for this component to the triggered checks
1193 nice_debug ("Agent %p : restarting check of %s:%s pair %p with "
1194 "USE-CANDIDATE attrib (regular nomination) for "
1195 "stream %d component %d", agent,
1196 priv_candidate_transport_to_string (
1197 this_component_pair->local->transport),
1198 priv_candidate_transport_to_string (
1199 this_component_pair->remote->transport),
1200 this_component_pair, stream->id, component->id);
1201 this_component_pair->use_candidate_on_next_check = TRUE;
1202 priv_add_pair_to_triggered_check_queue (agent, this_component_pair);
1203 keep_timer_going = TRUE;
1206 } else if (agent->controlling_mode) {
1207 for (i = stream->components; i; i = i->next) {
1208 NiceComponent *component = i->data;
1210 for (j = stream->conncheck_list; j ; j = j->next) {
1211 CandidateCheckPair *p = j->data;
1212 /* note: highest priority item selected (list always sorted) */
1213 if (p->component_id == component->id &&
1214 (p->state == NICE_CHECK_SUCCEEDED ||
1215 p->state == NICE_CHECK_DISCOVERED)) {
1216 nice_debug ("Agent %p : restarting check of pair %p as the "
1217 "nominated pair.", agent, p);
1218 p->nominated = TRUE;
1219 conn_check_update_selected_pair (agent, component, p);
1220 priv_add_pair_to_triggered_check_queue (agent, p);
1221 keep_timer_going = TRUE;
1222 break; /* move to the next component */
1228 if (stream->tick_counter++ % 50 == 0)
1229 nice_debug ("Agent %p : stream %u: timer tick #%u: %u frozen, "
1230 "%u in-progress, %u waiting, %u succeeded, %u discovered, "
1231 "%u nominated, %u waiting-for-nom, %u valid",
1232 agent, stream->id, stream->tick_counter,
1233 s_frozen, s_inprogress, s_waiting, s_succeeded, s_discovered,
1234 s_nominated, s_waiting_for_nomination, s_valid);
1236 return keep_timer_going;
1241 conn_check_stop (NiceAgent *agent)
1243 if (agent->conncheck_timer_source == NULL)
1246 g_source_destroy (agent->conncheck_timer_source);
1247 g_source_unref (agent->conncheck_timer_source);
1248 agent->conncheck_timer_source = NULL;
1249 agent->conncheck_ongoing_idle_delay = 0;
1254 * Timer callback that handles initiating and managing connectivity
1255 * checks (paced by the Ta timer).
1257 * This function is designed for the g_timeout_add() interface.
1259 * @return will return FALSE when no more pending timers.
1261 static gboolean priv_conn_check_tick_agent_locked (NiceAgent *agent,
1264 CandidateCheckPair *pair = NULL;
1265 gboolean keep_timer_going = FALSE;
1268 /* configure the initial state of the check lists of the agent
1269 * as described in ICE spec, 5.7.4
1271 * if all pairs in all check lists are in frozen state, then
1272 * we are in the initial state (5.7.4, point 1.)
1274 if (priv_number_of_active_check_lists (agent) == 0) {
1275 /* set some pairs of the first stream in the waiting state
1276 * ICE spec, 5.7.4, point 2.
1278 * note: we adapt the ICE spec here, by selecting the first
1279 * frozen check list, which is not necessarily the check
1280 * list of the first stream (the first stream may be completed)
1282 NiceStream *stream = priv_find_first_frozen_check_list (agent);
1284 priv_conn_check_unfreeze_next (agent, stream);
1287 /* step: perform a test from the triggered checks list,
1288 * ICE spec, 5.8 "Scheduling Checks"
1290 pair = priv_get_pair_from_triggered_check_queue (agent);
1293 priv_print_conn_check_lists (agent, G_STRFUNC,
1294 ", got a pair from triggered check list");
1295 if (conn_check_send (agent, pair)) {
1296 SET_PAIR_STATE (agent, pair, NICE_CHECK_FAILED);
1302 /* step: process ongoing STUN transactions and
1303 * perform an ordinary check, ICE spec, 5.8, "Scheduling Checks"
1305 for (i = agent->streams; i ; i = i->next) {
1306 NiceStream *stream = i->data;
1307 if (priv_conn_check_tick_stream (stream, agent))
1308 keep_timer_going = TRUE;
1309 if (priv_conn_check_tick_stream_nominate (stream, agent))
1310 keep_timer_going = TRUE;
1313 /* step: if no work left and a conncheck list of a stream is still
1314 * frozen, set the pairs to waiting, according to ICE SPEC, sect
1315 * 7.1.3.3. "Check List and Timer State Updates"
1317 if (!keep_timer_going) {
1318 for (i = agent->streams; i ; i = i->next) {
1319 NiceStream *stream = i->data;
1320 if (priv_is_checklist_frozen (stream)) {
1321 nice_debug ("Agent %p : stream %d conncheck list is still "
1322 "frozen, while other lists are completed. Unfreeze it.",
1324 keep_timer_going = priv_conn_check_unfreeze_next (agent, stream);
1326 if (!keep_timer_going && !stream->peer_gathering_done) {
1327 keep_timer_going = TRUE;
1332 /* note: we provide a grace period before declaring a component as
1333 * failed. Components marked connected, and then ready follow another
1334 * code path, and are not concerned by this grace period.
1336 if (!keep_timer_going && agent->conncheck_ongoing_idle_delay == 0)
1337 nice_debug ("Agent %p : waiting %d msecs before checking "
1338 "for failed components.", agent, agent->idle_timeout);
1340 if (keep_timer_going)
1341 agent->conncheck_ongoing_idle_delay = 0;
1343 agent->conncheck_ongoing_idle_delay += agent->timer_ta;
1345 /* step: stop timer if no work left */
1346 if (!keep_timer_going &&
1347 agent->conncheck_ongoing_idle_delay >= agent->idle_timeout) {
1348 nice_debug ("Agent %p : checking for failed components now.", agent);
1349 for (i = agent->streams; i; i = i->next) {
1350 NiceStream *stream = i->data;
1351 priv_update_check_list_failed_components (agent, stream);
1352 for (j = stream->components; j; j = j->next) {
1353 NiceComponent *component = j->data;
1354 conn_check_update_check_list_state_for_ready (agent, stream, component);
1358 nice_debug ("Agent %p : %s: stopping conncheck timer", agent, G_STRFUNC);
1359 priv_print_conn_check_lists (agent, G_STRFUNC,
1360 ", conncheck timer stopped");
1362 /* Stopping the timer so destroy the source.. this will allow
1363 the timer to be reset if we get a set_remote_candidates after this
1365 conn_check_stop (agent);
1367 /* XXX: what to signal, is all processing now really done? */
1368 nice_debug ("Agent %p : changing conncheck state to COMPLETED.", agent);
1375 static gboolean priv_conn_keepalive_retransmissions_tick_agent_locked (
1376 NiceAgent *agent, gpointer pointer)
1378 CandidatePair *pair = (CandidatePair *) pointer;
1380 g_source_destroy (pair->keepalive.tick_source);
1381 g_source_unref (pair->keepalive.tick_source);
1382 pair->keepalive.tick_source = NULL;
1384 switch (stun_timer_refresh (&pair->keepalive.timer)) {
1385 case STUN_USAGE_TIMER_RETURN_TIMEOUT:
1388 StunTransactionId id;
1389 NiceComponent *component;
1391 if (!agent_find_component (agent,
1392 pair->keepalive.stream_id, pair->keepalive.component_id,
1393 NULL, &component)) {
1394 nice_debug ("Could not find stream or component in"
1395 " priv_conn_keepalive_retransmissions_tick");
1399 stun_message_id (&pair->keepalive.stun_message, id);
1400 stun_agent_forget_transaction (&component->stun_agent, id);
1401 pair->keepalive.stun_message.buffer = NULL;
1403 if (agent->media_after_tick) {
1404 nice_debug ("Agent %p : Keepalive conncheck timed out!! "
1405 "but media was received. Suspecting keepalive lost because of "
1406 "network bottleneck", agent);
1408 nice_debug ("Agent %p : Keepalive conncheck timed out!! "
1409 "peer probably lost connection", agent);
1410 agent_signal_component_state_change (agent,
1411 pair->keepalive.stream_id, pair->keepalive.component_id,
1412 NICE_COMPONENT_STATE_FAILED);
1416 case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
1418 agent_socket_send (pair->local->sockptr, &pair->remote->addr,
1419 stun_message_length (&pair->keepalive.stun_message),
1420 (gchar *)pair->keepalive.stun_buffer);
1422 nice_debug ("Agent %p : Retransmitting keepalive conncheck",
1426 case STUN_USAGE_TIMER_RETURN_SUCCESS:
1427 agent_timeout_add_with_context (agent,
1428 &pair->keepalive.tick_source,
1429 "Pair keepalive", stun_timer_remainder (&pair->keepalive.timer),
1430 priv_conn_keepalive_retransmissions_tick_agent_locked, pair);
1433 g_assert_not_reached();
1440 static guint32 peer_reflexive_candidate_priority (NiceAgent *agent,
1441 NiceCandidate *local_candidate)
1443 NiceCandidate *candidate_priority =
1444 nice_candidate_new (NICE_CANDIDATE_TYPE_PEER_REFLEXIVE);
1447 candidate_priority->transport = local_candidate->transport;
1448 candidate_priority->component_id = local_candidate->component_id;
1449 candidate_priority->base_addr = local_candidate->addr;
1450 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
1451 priority = nice_candidate_jingle_priority (candidate_priority);
1452 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
1453 agent->compatibility == NICE_COMPATIBILITY_OC2007) {
1454 priority = nice_candidate_msn_priority (candidate_priority);
1455 } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
1456 priority = nice_candidate_ms_ice_priority (candidate_priority,
1457 agent->reliable, FALSE);
1459 priority = nice_candidate_ice_priority (candidate_priority,
1460 agent->reliable, FALSE);
1462 nice_candidate_free (candidate_priority);
1467 /* Returns the priority of a local candidate of type peer-reflexive that
1468 * would be learned as a consequence of a check from this local
1469 * candidate. See RFC 5245, section 7.1.2.1. "PRIORITY and USE-CANDIDATE".
1470 * RFC 5245 is more explanatory than RFC 8445 on this detail.
1472 * Apply to local candidates of type host only, because candidates of type
1473 * relay are supposed to have a public IP address, that wont generate
1474 * a peer-reflexive address. Server-reflexive candidates are not
1475 * concerned too, because no STUN request is sent with a local candidate
1478 static guint32 stun_request_priority (NiceAgent *agent,
1479 NiceCandidate *local_candidate)
1481 if (local_candidate->type == NICE_CANDIDATE_TYPE_HOST)
1482 return peer_reflexive_candidate_priority (agent, local_candidate);
1484 return local_candidate->priority;
1487 static void ms_ice2_legacy_conncheck_send(StunMessage *msg, NiceSocket *sock,
1488 const NiceAddress *remote_addr)
1490 uint32_t *fingerprint_attr;
1491 uint32_t fingerprint_orig;
1492 uint16_t fingerprint_len;
1495 if (msg->agent->ms_ice2_send_legacy_connchecks == FALSE) {
1499 fingerprint_attr = (uint32_t *)stun_message_find (msg,
1500 STUN_ATTRIBUTE_FINGERPRINT, &fingerprint_len);
1502 if (fingerprint_attr == NULL) {
1503 nice_debug ("FINGERPRINT not found.");
1507 if (fingerprint_len != sizeof (fingerprint_orig)) {
1508 nice_debug ("Unexpected FINGERPRINT length %u.", fingerprint_len);
1512 memcpy (&fingerprint_orig, fingerprint_attr, sizeof (fingerprint_orig));
1514 buffer_len = stun_message_length (msg);
1516 *fingerprint_attr = stun_fingerprint (msg->buffer, buffer_len, TRUE);
1518 agent_socket_send (sock, remote_addr, buffer_len, (gchar *)msg->buffer);
1520 memcpy (fingerprint_attr, &fingerprint_orig, sizeof (fingerprint_orig));
1524 * Timer callback that handles initiating and managing connectivity
1525 * checks (paced by the Ta timer).
1527 * This function is designed for the g_timeout_add() interface.
1529 * @return will return FALSE when no more pending timers.
1531 static gboolean priv_conn_keepalive_tick_unlocked (NiceAgent *agent)
1537 guint64 min_next_tick;
1538 guint64 next_timer_tick;
1540 now = g_get_monotonic_time ();
1541 min_next_tick = now + 1000 * NICE_AGENT_TIMER_TR_DEFAULT;
1543 /* case 1: session established and media flowing
1544 * (ref ICE sect 11 "Keepalives" RFC-8445)
1545 * TODO: keepalives should be send only when no packet has been sent
1546 * on that pair in the last Tr seconds, and not unconditionally.
1548 for (i = agent->streams; i; i = i->next) {
1550 NiceStream *stream = i->data;
1551 for (j = stream->components; j; j = j->next) {
1552 NiceComponent *component = j->data;
1553 if (component->selected_pair.local != NULL) {
1554 CandidatePair *p = &component->selected_pair;
1556 /* Disable keepalive checks on TCP candidates unless explicitly enabled */
1557 if (p->local->transport != NICE_CANDIDATE_TRANSPORT_UDP &&
1558 !agent->keepalive_conncheck)
1561 if (p->keepalive.next_tick) {
1562 if (p->keepalive.next_tick < min_next_tick)
1563 min_next_tick = p->keepalive.next_tick;
1564 if (now < p->keepalive.next_tick)
1568 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE ||
1569 agent->keepalive_conncheck) {
1570 uint8_t uname[NICE_STREAM_MAX_UNAME];
1572 priv_create_username (agent, agent_find_stream (agent, stream->id),
1573 component->id, p->remote, p->local, uname, sizeof (uname),
1575 uint8_t *password = NULL;
1576 size_t password_len = priv_get_password (agent,
1577 agent_find_stream (agent, stream->id), p->remote, &password);
1579 if (p->keepalive.stun_message.buffer != NULL) {
1580 nice_debug ("Agent %p: Keepalive for s%u:c%u still"
1581 " retransmitting, not restarting", agent, stream->id,
1586 if (nice_debug_is_enabled ()) {
1587 gchar tmpbuf[INET6_ADDRSTRLEN];
1588 nice_address_to_string (&p->remote->addr, tmpbuf);
1589 nice_debug ("Agent %p : Keepalive STUN-CC REQ to '%s:%u', "
1590 "(c-id:%u), username='%.*s' (%" G_GSIZE_FORMAT "), "
1591 "password='%.*s' (%" G_GSIZE_FORMAT "), priority=%08x.",
1592 agent, tmpbuf, nice_address_get_port (&p->remote->addr),
1593 component->id, (int) uname_len, uname, uname_len,
1594 (int) password_len, password, password_len,
1597 if (uname_len > 0) {
1598 buf_len = stun_usage_ice_conncheck_create (&component->stun_agent,
1599 &p->keepalive.stun_message, p->keepalive.stun_buffer,
1600 sizeof(p->keepalive.stun_buffer),
1601 uname, uname_len, password, password_len,
1602 agent->controlling_mode, agent->controlling_mode,
1606 agent_to_ice_compatibility (agent));
1608 nice_debug ("Agent %p: conncheck created %zd - %p",
1609 agent, buf_len, p->keepalive.stun_message.buffer);
1612 stun_timer_start (&p->keepalive.timer,
1613 agent->stun_initial_timeout,
1614 agent->stun_max_retransmissions);
1616 agent->media_after_tick = FALSE;
1618 /* send the conncheck */
1619 agent_socket_send (p->local->sockptr, &p->remote->addr,
1620 buf_len, (gchar *)p->keepalive.stun_buffer);
1622 p->keepalive.stream_id = stream->id;
1623 p->keepalive.component_id = component->id;
1624 p->keepalive.next_tick = now + 1000 * NICE_AGENT_TIMER_TR_DEFAULT;
1626 agent_timeout_add_with_context (agent,
1627 &p->keepalive.tick_source, "Pair keepalive",
1628 stun_timer_remainder (&p->keepalive.timer),
1629 priv_conn_keepalive_retransmissions_tick_agent_locked, p);
1631 next_timer_tick = now + agent->timer_ta * 1000;
1638 buf_len = stun_usage_bind_keepalive (&component->stun_agent,
1639 &p->keepalive.stun_message, p->keepalive.stun_buffer,
1640 sizeof(p->keepalive.stun_buffer));
1643 agent_socket_send (p->local->sockptr, &p->remote->addr, buf_len,
1644 (gchar *)p->keepalive.stun_buffer);
1646 p->keepalive.next_tick = now + 1000 * NICE_AGENT_TIMER_TR_DEFAULT;
1648 if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
1649 ms_ice2_legacy_conncheck_send (&p->keepalive.stun_message,
1650 p->local->sockptr, &p->remote->addr);
1653 if (nice_debug_is_enabled ()) {
1654 gchar tmpbuf[INET6_ADDRSTRLEN];
1655 nice_address_to_string (&p->local->base_addr, tmpbuf);
1656 nice_debug ("Agent %p : resending STUN to keep the "
1657 "selected base address %s:%u alive in s%d/c%d.", agent,
1658 tmpbuf, nice_address_get_port (&p->local->base_addr),
1659 stream->id, component->id);
1662 next_timer_tick = now + agent->timer_ta * 1000;
1672 /* case 2: connectivity establishment ongoing
1673 * (ref ICE sect 5.1.1.4 "Keeping Candidates Alive" RFC-8445)
1675 for (i = agent->streams; i; i = i->next) {
1676 NiceStream *stream = i->data;
1677 for (j = stream->components; j; j = j->next) {
1678 NiceComponent *component = j->data;
1679 if (component->state < NICE_COMPONENT_STATE_CONNECTED &&
1680 agent->stun_server_ip) {
1681 NiceAddress stun_server;
1682 if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
1683 StunAgent stun_agent;
1684 uint8_t stun_buffer[STUN_MAX_MESSAGE_SIZE_IPV6];
1685 StunMessage stun_message;
1686 size_t buffer_len = 0;
1688 nice_address_set_port (&stun_server, agent->stun_server_port);
1690 nice_agent_init_stun_agent (agent, &stun_agent);
1692 buffer_len = stun_usage_bind_create (&stun_agent,
1693 &stun_message, stun_buffer, sizeof(stun_buffer));
1695 for (k = component->local_candidates; k; k = k->next) {
1696 NiceCandidate *candidate = (NiceCandidate *) k->data;
1697 if (candidate->type == NICE_CANDIDATE_TYPE_HOST &&
1698 candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP &&
1699 nice_address_ip_version (&candidate->addr) ==
1700 nice_address_ip_version (&stun_server)) {
1702 if (candidate->keepalive_next_tick) {
1703 if (candidate->keepalive_next_tick < min_next_tick)
1704 min_next_tick = candidate->keepalive_next_tick;
1705 if (now < candidate->keepalive_next_tick)
1709 /* send the conncheck */
1710 if (nice_debug_is_enabled ()) {
1711 gchar tmpbuf[INET6_ADDRSTRLEN];
1712 nice_address_to_string (&candidate->addr, tmpbuf);
1713 nice_debug ("Agent %p : resending STUN to keep the local "
1714 "candidate %s:%u alive in s%d/c%d.", agent,
1715 tmpbuf, nice_address_get_port (&candidate->addr),
1716 stream->id, component->id);
1718 agent_socket_send (candidate->sockptr, &stun_server,
1719 buffer_len, (gchar *)stun_buffer);
1720 candidate->keepalive_next_tick = now +
1721 1000 * NICE_AGENT_TIMER_TR_DEFAULT;
1722 next_timer_tick = now + agent->timer_ta * 1000;
1731 next_timer_tick = min_next_tick;
1735 nice_debug ("Agent %p : %s: stopping keepalive timer", agent, G_STRFUNC);
1739 if (agent->keepalive_timer_source) {
1740 g_source_destroy (agent->keepalive_timer_source);
1741 g_source_unref (agent->keepalive_timer_source);
1742 agent->keepalive_timer_source = NULL;
1744 agent_timeout_add_with_context (agent, &agent->keepalive_timer_source,
1745 "Connectivity keepalive timeout", (next_timer_tick - now)/ 1000,
1746 priv_conn_keepalive_tick_agent_locked, NULL);
1750 static gboolean priv_conn_keepalive_tick_agent_locked (NiceAgent *agent,
1755 ret = priv_conn_keepalive_tick_unlocked (agent);
1757 if (agent->keepalive_timer_source) {
1758 g_source_destroy (agent->keepalive_timer_source);
1759 g_source_unref (agent->keepalive_timer_source);
1760 agent->keepalive_timer_source = NULL;
1768 static gboolean priv_turn_allocate_refresh_retransmissions_tick_agent_locked (
1769 NiceAgent *agent, gpointer pointer)
1771 CandidateRefresh *cand = (CandidateRefresh *) pointer;
1773 g_source_destroy (cand->tick_source);
1774 g_source_unref (cand->tick_source);
1775 cand->tick_source = NULL;
1777 switch (stun_timer_refresh (&cand->timer)) {
1778 case STUN_USAGE_TIMER_RETURN_TIMEOUT:
1781 StunTransactionId id;
1783 stun_message_id (&cand->stun_message, id);
1784 stun_agent_forget_transaction (&cand->stun_agent, id);
1786 refresh_free (agent, cand);
1789 case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
1791 agent_socket_send (cand->nicesock, &cand->server,
1792 stun_message_length (&cand->stun_message), (gchar *)cand->stun_buffer);
1795 case STUN_USAGE_TIMER_RETURN_SUCCESS:
1796 agent_timeout_add_with_context (agent, &cand->tick_source,
1797 "Candidate TURN refresh", stun_timer_remainder (&cand->timer),
1798 priv_turn_allocate_refresh_retransmissions_tick_agent_locked, cand);
1801 /* Nothing to do. */
1805 return G_SOURCE_REMOVE;
1808 static void priv_turn_allocate_refresh_tick_unlocked (NiceAgent *agent,
1809 CandidateRefresh *cand)
1815 size_t buffer_len = 0;
1816 StunUsageTurnCompatibility turn_compat =
1817 agent_to_turn_compatibility (agent);
1819 username = (uint8_t *)cand->candidate->turn->username;
1820 username_len = (size_t) strlen (cand->candidate->turn->username);
1821 password = (uint8_t *)cand->candidate->turn->password;
1822 password_len = (size_t) strlen (cand->candidate->turn->password);
1824 if (turn_compat == STUN_USAGE_TURN_COMPATIBILITY_MSN ||
1825 turn_compat == STUN_USAGE_TURN_COMPATIBILITY_OC2007) {
1826 username = cand->candidate->turn->decoded_username;
1827 password = cand->candidate->turn->decoded_password;
1828 username_len = cand->candidate->turn->decoded_username_len;
1829 password_len = cand->candidate->turn->decoded_password_len;
1832 buffer_len = stun_usage_turn_create_refresh (&cand->stun_agent,
1833 &cand->stun_message, cand->stun_buffer, sizeof(cand->stun_buffer),
1834 cand->stun_resp_msg.buffer == NULL ? NULL : &cand->stun_resp_msg, -1,
1835 username, username_len,
1836 password, password_len,
1839 nice_debug ("Agent %p : Sending allocate Refresh %zd", agent,
1842 if (cand->tick_source != NULL) {
1843 g_source_destroy (cand->tick_source);
1844 g_source_unref (cand->tick_source);
1845 cand->tick_source = NULL;
1848 if (buffer_len > 0) {
1849 stun_timer_start (&cand->timer,
1850 agent->stun_initial_timeout,
1851 agent->stun_max_retransmissions);
1853 /* send the refresh */
1854 agent_socket_send (cand->nicesock, &cand->server,
1855 buffer_len, (gchar *)cand->stun_buffer);
1857 agent_timeout_add_with_context (agent, &cand->tick_source,
1858 "Candidate TURN refresh", stun_timer_remainder (&cand->timer),
1859 priv_turn_allocate_refresh_retransmissions_tick_agent_locked, cand);
1866 * Timer callback that handles refreshing TURN allocations
1868 * This function is designed for the g_timeout_add() interface.
1870 * @return will return FALSE when no more pending timers.
1872 static gboolean priv_turn_allocate_refresh_tick_agent_locked (NiceAgent *agent,
1875 CandidateRefresh *cand = (CandidateRefresh *) pointer;
1877 priv_turn_allocate_refresh_tick_unlocked (agent, cand);
1879 return G_SOURCE_REMOVE;
1884 * Initiates the next pending connectivity check.
1886 void conn_check_schedule_next (NiceAgent *agent)
1888 if (agent->discovery_unsched_items > 0)
1889 nice_debug ("Agent %p : WARN: starting conn checks before local candidate gathering is finished.", agent);
1891 /* step: schedule timer if not running yet */
1892 if (agent->conncheck_timer_source == NULL) {
1893 agent_timeout_add_with_context (agent, &agent->conncheck_timer_source,
1894 "Connectivity check schedule", agent->timer_ta,
1895 priv_conn_check_tick_agent_locked, NULL);
1898 /* step: also start the keepalive timer */
1899 if (agent->keepalive_timer_source == NULL) {
1900 agent_timeout_add_with_context (agent, &agent->keepalive_timer_source,
1901 "Connectivity keepalive timeout", agent->timer_ta,
1902 priv_conn_keepalive_tick_agent_locked, NULL);
1907 * Compares two connectivity check items. Checkpairs are sorted
1908 * in descending priority order, with highest priority item at
1909 * the start of the list.
1911 gint conn_check_compare (const CandidateCheckPair *a, const CandidateCheckPair *b)
1913 if (a->priority > b->priority)
1915 else if (a->priority < b->priority)
1920 /* Find a transport compatible with a given socket.
1922 * Returns TRUE when a matching transport can be guessed from
1923 * the type of the socket in an unambiguous way.
1926 nice_socket_has_compatible_transport (NiceSocket *socket,
1927 NiceCandidateTransport *transport)
1929 gboolean found = TRUE;
1932 g_assert (transport);
1934 switch (socket->type) {
1935 case NICE_SOCKET_TYPE_TCP_BSD:
1936 if (nice_tcp_bsd_socket_get_passive_parent (socket))
1937 *transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
1939 *transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
1941 case NICE_SOCKET_TYPE_TCP_PASSIVE:
1942 *transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
1944 case NICE_SOCKET_TYPE_TCP_ACTIVE:
1945 *transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
1947 case NICE_SOCKET_TYPE_UDP_BSD:
1948 *transport = NICE_CANDIDATE_TRANSPORT_UDP;
1957 /* Test if a local socket and a local candidate are compatible. This
1958 * function does supplementary tests when the address and port are not
1959 * sufficient to give a unique candidate. We try to avoid comparing
1960 * directly the sockptr value, when possible, to rely on objective
1961 * properties of the candidate and the socket instead, and we also
1962 * choose to ignore the conncheck list for the same reason.
1965 local_candidate_and_socket_compatible (NiceAgent *agent,
1966 NiceCandidate *lcand, NiceSocket *socket)
1968 gboolean ret = TRUE;
1969 NiceCandidateTransport transport;
1974 if (nice_socket_has_compatible_transport (socket, &transport)) {
1975 ret = (lcand->transport == transport);
1976 /* tcp-active discovered peer-reflexive local candidate, where
1977 * socket is the tcp connect related socket */
1978 if (ret && transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE &&
1979 nice_address_get_port (&lcand->addr) > 0)
1980 ret = (lcand->sockptr == socket);
1981 } else if (socket->type == NICE_SOCKET_TYPE_UDP_TURN)
1982 /* Socket of type udp-turn will match a unique local candidate
1983 * by its sockptr value. An an udp-turn socket doesn't carry enough
1984 * information when base socket is udp-turn-over-tcp to disambiguate
1985 * between a tcp-act and a tcp-pass local candidate.
1987 ret = (lcand->sockptr == socket);
1992 /* Test if a local socket and a remote candidate are compatible.
1993 * This function is very close to its local candidate counterpart,
1994 * the difference is that we also use information from the local
1995 * candidate we may have identified previously. This is needed
1996 * to disambiguate the transport of the candidate with a socket
2001 remote_candidate_and_socket_compatible (NiceAgent *agent,
2002 NiceCandidate *lcand, NiceCandidate *rcand, NiceSocket *socket)
2004 gboolean ret = TRUE;
2005 NiceCandidateTransport transport;
2010 if (nice_socket_has_compatible_transport (socket, &transport))
2011 ret = (conn_check_match_transport (rcand->transport) == transport);
2013 /* This supplementary test with the local candidate is needed with
2014 * socket of type udp-turn, the type doesn't allow to disambiguate
2015 * between a tcp-pass and a tcp-act remote candidate
2018 ret = (conn_check_match_transport (lcand->transport) == rcand->transport);
2024 conn_check_remote_candidates_set(NiceAgent *agent, NiceStream *stream,
2025 NiceComponent *component)
2029 NiceCandidate *lcand = NULL, *rcand = NULL;
2031 nice_debug ("Agent %p : conn_check_remote_candidates_set %u %u",
2032 agent, stream->id, component->id);
2034 if (stream->remote_ufrag[0] == 0)
2037 if (component->incoming_checks.head)
2038 nice_debug ("Agent %p : credentials have been set, "
2039 "we can process incoming checks", agent);
2041 for (i = component->incoming_checks.head; i;) {
2042 IncomingCheck *icheck = i->data;
2043 GList *i_next = i->next;
2045 nice_debug ("Agent %p : replaying icheck=%p (sock=%p)",
2046 agent, icheck, icheck->local_socket);
2048 /* sect 7.2.1.3., "Learning Peer Reflexive Candidates", has to
2049 * be handled separately */
2050 for (j = component->local_candidates; j; j = j->next) {
2051 NiceCandidate *cand = j->data;
2054 if (cand->type == NICE_CANDIDATE_TYPE_RELAYED)
2057 addr = &cand->base_addr;
2059 if (nice_address_equal (&icheck->local_socket->addr, addr) &&
2060 local_candidate_and_socket_compatible (agent, cand,
2061 icheck->local_socket)) {
2067 g_assert (lcand != NULL);
2069 for (j = component->remote_candidates; j; j = j->next) {
2070 NiceCandidate *cand = j->data;
2071 if (nice_address_equal (&cand->addr, &icheck->from) &&
2072 remote_candidate_and_socket_compatible (agent, lcand, cand,
2073 icheck->local_socket)) {
2079 if (lcand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) {
2080 CandidateCheckPair *pair = NULL;
2082 for (j = stream->conncheck_list; j; j = j->next) {
2083 CandidateCheckPair *p = j->data;
2084 if (lcand == p->local && rcand == p->remote) {
2090 pair = priv_conn_check_add_for_candidate_pair_matched (agent,
2091 stream->id, component, lcand, rcand, NICE_CHECK_SUCCEEDED);
2097 priv_schedule_triggered_check (agent, stream, component,
2098 icheck->local_socket, rcand);
2099 if (icheck->use_candidate)
2100 priv_mark_pair_nominated (agent, stream, component, lcand, rcand);
2102 if (icheck->username)
2103 g_free (icheck->username);
2104 g_slice_free (IncomingCheck, icheck);
2105 g_queue_delete_link (&component->incoming_checks, i);
2111 * Handle any processing steps for connectivity checks after
2112 * remote credentials have been set. This function handles
2113 * the special case where answerer has sent us connectivity
2114 * checks before the answer (containing credentials information),
2115 * reaches us. The special case is documented in RFC 5245 sect 7.2.
2118 void conn_check_remote_credentials_set(NiceAgent *agent, NiceStream *stream)
2122 for (j = stream->components; j ; j = j->next) {
2123 NiceComponent *component = j->data;
2125 conn_check_remote_candidates_set(agent, stream, component);
2130 * Enforces the upper limit for connectivity checks by dropping
2131 * lower-priority pairs as described RFC 8445 section 6.1.2.5. See also
2132 * conn_check_add_for_candidate().
2133 * Returns TRUE if the pair in argument is one of the deleted pairs.
2135 static gboolean priv_limit_conn_check_list_size (NiceAgent *agent,
2136 NiceStream *stream, CandidateCheckPair *pair)
2139 guint cancelled = 0;
2140 gboolean deleted = FALSE;
2141 GSList *item = stream->conncheck_list;
2144 CandidateCheckPair *p = item->data;
2145 GSList *next = item->next;
2148 /* We remove lower-priority pairs, but only the ones that can be
2149 * safely discarded without breaking an ongoing conncheck process.
2150 * This only includes pairs that are in the frozen state (those
2151 * initially added when remote candidates are received) or in failed
2152 * state. Pairs in any other state play a role in the conncheck, and
2153 * there removal may lead to a failing conncheck that would succeed
2156 * We also remove failed pairs from the list unconditionally.
2158 if ((valid > agent->max_conn_checks && p->state == NICE_CHECK_FROZEN) ||
2159 p->state == NICE_CHECK_FAILED) {
2162 nice_debug ("Agent %p : pair %p removed.", agent, p);
2163 candidate_check_pair_free (agent, p);
2164 stream->conncheck_list = g_slist_delete_link (stream->conncheck_list,
2172 nice_debug ("Agent %p : Pruned %d pairs. "
2173 "Conncheck list has %d elements left. "
2174 "Maximum connchecks allowed : %d", agent, cancelled,
2175 valid - cancelled, agent->max_conn_checks);
2181 * Changes the selected pair for the component if 'pair'
2182 * has higher priority than the currently selected pair. See
2183 * RFC 8445 sect 8.1.1. "Nominating Pairs"
2186 conn_check_update_selected_pair (NiceAgent *agent, NiceComponent *component,
2187 CandidateCheckPair *pair)
2189 CandidatePair cpair = { 0, };
2191 g_assert (component);
2193 /* pair is expected to have the nominated flag */
2194 g_assert (pair->nominated);
2195 if (pair->priority > component->selected_pair.priority) {
2196 gchar priority[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE];
2197 nice_candidate_pair_priority_to_string (pair->priority, priority);
2198 nice_debug ("Agent %p : changing SELECTED PAIR for component %u: %s:%s "
2199 "(prio:%s).", agent, component->id,
2200 pair->local->foundation, pair->remote->foundation, priority);
2202 cpair.local = pair->local;
2203 cpair.remote = pair->remote;
2204 cpair.priority = pair->priority;
2205 cpair.stun_priority = pair->stun_priority;
2207 nice_component_update_selected_pair (agent, component, &cpair);
2209 priv_conn_keepalive_tick_unlocked (agent);
2211 agent_signal_new_selected_pair (agent, pair->stream_id, component->id,
2212 pair->local, pair->remote);
2217 * Updates the check list state.
2219 * Implements parts of the algorithm described in
2220 * ICE sect 8.1.2. "Updating States" (RFC 5245): if for any
2221 * component, all checks have been completed and have
2222 * failed to produce a nominated pair, mark that component's
2223 * state to NICE_CHECK_FAILED.
2225 * Sends a component state changesignal via 'agent'.
2227 static void priv_update_check_list_failed_components (NiceAgent *agent, NiceStream *stream)
2232 /* note: emitting a signal might cause the client
2233 * to remove the stream, thus the component count
2234 * must be fetched before entering the loop*/
2235 guint c, components = stream->n_components;
2237 if (stream->conncheck_list == NULL)
2240 for (i = agent->discovery_list; i; i = i->next) {
2241 CandidateDiscovery *d = i->data;
2243 /* There is still discovery ogoing for this stream,
2244 * so don't fail any of it's candidates.
2246 if (d->stream_id == stream->id && !d->done)
2249 if (agent->discovery_list != NULL)
2252 /* note: iterate the conncheck list for each component separately */
2253 for (c = 0; c < components; c++) {
2254 NiceComponent *component = NULL;
2255 if (!agent_find_component (agent, stream->id, c+1, NULL, &component))
2260 for (i = stream->conncheck_list; i; i = i->next) {
2261 CandidateCheckPair *p = i->data;
2263 g_assert_cmpuint (p->stream_id, ==, stream->id);
2265 if (p->component_id == (c + 1)) {
2268 if (p->state != NICE_CHECK_FAILED &&
2269 p->state != NICE_CHECK_SUCCEEDED &&
2270 p->state != NICE_CHECK_DISCOVERED)
2275 /* note: all pairs are either failed or succeeded, and the component
2276 * has not produced a nominated pair.
2277 * Set the component to FAILED only if it actually had remote candidates
2279 if (completed && nominated == 0 &&
2280 component != NULL && component->remote_candidates != NULL)
2281 agent_signal_component_state_change (agent,
2283 (c + 1), /* component-id */
2284 NICE_COMPONENT_STATE_FAILED);
2289 * Updates the check list state for a stream component.
2291 * Implements the algorithm described in ICE sect 8.1.2
2292 * "Updating States" (ID-19) as it applies to checks of
2293 * a certain component. If there are any nominated pairs,
2294 * ICE processing may be concluded, and component state is
2297 * Sends a component state changesignal via 'agent'.
2299 void conn_check_update_check_list_state_for_ready (NiceAgent *agent,
2300 NiceStream *stream, NiceComponent *component)
2303 guint valid = 0, nominated = 0;
2305 g_assert (component);
2307 /* step: search for at least one nominated pair */
2308 for (i = stream->conncheck_list; i; i = i->next) {
2309 CandidateCheckPair *p = i->data;
2310 if (p->component_id == component->id) {
2313 if (p->nominated == TRUE) {
2320 if (nominated > 0) {
2321 /* Only go to READY if no checks are left in progress. If there are
2322 * any that are kept, then this function will be called again when the
2323 * conncheck tick timer finishes them all */
2324 if (priv_prune_pending_checks (agent, stream, component) == 0) {
2325 /* Continue through the states to give client code a nice
2326 * logical progression. See http://phabricator.freedesktop.org/D218 for
2328 if (component->state < NICE_COMPONENT_STATE_CONNECTING ||
2329 component->state == NICE_COMPONENT_STATE_FAILED)
2330 agent_signal_component_state_change (agent, stream->id, component->id,
2331 NICE_COMPONENT_STATE_CONNECTING);
2332 if (component->state < NICE_COMPONENT_STATE_CONNECTED)
2333 agent_signal_component_state_change (agent, stream->id, component->id,
2334 NICE_COMPONENT_STATE_CONNECTED);
2335 agent_signal_component_state_change (agent, stream->id,
2336 component->id, NICE_COMPONENT_STATE_READY);
2339 nice_debug ("Agent %p : conn.check list status: %u nominated, %u valid, c-id %u.", agent, nominated, valid, component->id);
2343 * The remote party has signalled that the candidate pair
2344 * described by 'component' and 'remotecand' is nominated
2347 static void priv_mark_pair_nominated (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceCandidate *localcand, NiceCandidate *remotecand)
2351 g_assert (component);
2353 if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) &&
2354 agent->controlling_mode)
2357 /* step: search for at least one nominated pair */
2358 for (i = stream->conncheck_list; i; i = i->next) {
2359 CandidateCheckPair *pair = i->data;
2360 if (pair->local == localcand && pair->remote == remotecand) {
2361 /* ICE, 7.2.1.5. Updating the Nominated Flag */
2362 /* note: TCP candidates typically produce peer reflexive
2363 * candidate, generating a "discovered" pair that can be
2366 if (pair->state == NICE_CHECK_SUCCEEDED &&
2367 pair->discovered_pair != NULL) {
2368 pair = pair->discovered_pair;
2369 g_assert_cmpint (pair->state, ==, NICE_CHECK_DISCOVERED);
2372 /* If the state of this pair is In-Progress, [...] the resulting
2373 * valid pair has its nominated flag set when the response
2376 if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) &&
2377 pair->state == NICE_CHECK_IN_PROGRESS) {
2378 pair->mark_nominated_on_response_arrival = TRUE;
2379 nice_debug ("Agent %p : pair %p (%s) is in-progress, "
2380 "will be nominated on response receipt.",
2381 agent, pair, pair->foundation);
2385 !NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
2386 nice_debug ("Agent %p : marking pair %p (%s) as nominated",
2387 agent, pair, pair->foundation);
2388 pair->nominated = TRUE;
2392 /* Do not step down to CONNECTED if we're already at state READY*/
2393 if (component->state == NICE_COMPONENT_STATE_FAILED)
2394 agent_signal_component_state_change (agent,
2395 stream->id, component->id, NICE_COMPONENT_STATE_CONNECTING);
2396 conn_check_update_selected_pair (agent, component, pair);
2397 if (component->state == NICE_COMPONENT_STATE_CONNECTING)
2398 /* step: notify the client of a new component state (must be done
2399 * before the possible check list state update step */
2400 agent_signal_component_state_change (agent,
2401 stream->id, component->id, NICE_COMPONENT_STATE_CONNECTED);
2404 if (pair->nominated)
2405 conn_check_update_check_list_state_for_ready (agent, stream, component);
2411 * Creates a new connectivity check pair and adds it to
2412 * the agent's list of checks.
2414 static CandidateCheckPair *priv_add_new_check_pair (NiceAgent *agent,
2415 guint stream_id, NiceComponent *component, NiceCandidate *local,
2416 NiceCandidate *remote, NiceCheckState initial_state)
2419 CandidateCheckPair *pair;
2422 g_assert (local != NULL);
2423 g_assert (remote != NULL);
2425 priority = agent_candidate_pair_priority (agent, local, remote);
2427 if (component->selected_pair.priority &&
2428 priority < component->selected_pair.priority) {
2429 gchar prio1[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE];
2430 gchar prio2[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE];
2432 nice_candidate_pair_priority_to_string (priority, prio1);
2433 nice_candidate_pair_priority_to_string (component->selected_pair.priority,
2435 nice_debug ("Agent %p : do not create a pair that would have a priority "
2436 "%s lower than selected pair priority %s.", agent, prio1, prio2);
2440 stream = agent_find_stream (agent, stream_id);
2441 pair = g_slice_new0 (CandidateCheckPair);
2443 pair->stream_id = stream_id;
2444 pair->component_id = component->id;;
2445 pair->local = local;
2446 pair->remote = remote;
2447 /* note: we use the remote sockptr only in the case
2450 if (local->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE &&
2451 remote->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE)
2452 pair->sockptr = (NiceSocket *) remote->sockptr;
2454 pair->sockptr = (NiceSocket *) local->sockptr;
2455 g_snprintf (pair->foundation, NICE_CANDIDATE_PAIR_MAX_FOUNDATION, "%s:%s", local->foundation, remote->foundation);
2457 pair->priority = agent_candidate_pair_priority (agent, local, remote);
2458 nice_debug ("Agent %p : creating a new pair", agent);
2459 SET_PAIR_STATE (agent, pair, initial_state);
2461 gchar tmpbuf1[INET6_ADDRSTRLEN];
2462 gchar tmpbuf2[INET6_ADDRSTRLEN];
2463 nice_address_to_string (&pair->local->addr, tmpbuf1);
2464 nice_address_to_string (&pair->remote->addr, tmpbuf2);
2465 nice_debug ("Agent %p : new pair %p : [%s]:%u --> [%s]:%u", agent, pair,
2466 tmpbuf1, nice_address_get_port (&pair->local->addr),
2467 tmpbuf2, nice_address_get_port (&pair->remote->addr));
2469 pair->stun_priority = stun_request_priority (agent, local);
2471 stream->conncheck_list = g_slist_insert_sorted (stream->conncheck_list, pair,
2472 (GCompareFunc)conn_check_compare);
2474 nice_debug ("Agent %p : added a new pair %p with foundation '%s' and "
2475 "transport %s:%s to stream %u component %u",
2476 agent, pair, pair->foundation,
2477 priv_candidate_transport_to_string (pair->local->transport),
2478 priv_candidate_transport_to_string (pair->remote->transport),
2479 stream_id, component->id);
2481 /* If this is the first pair added into the check list and the first stream's
2482 * components already have valid pairs, unfreeze the pair as it would happen
2483 * in priv_conn_check_unfreeze_related() were the list not empty. */
2484 if (stream != agent->streams->data &&
2485 g_slist_length (stream->conncheck_list) == 1 &&
2486 priv_all_components_have_valid_pair (agent->streams->data)) {
2487 nice_debug ("Agent %p : %p is the first pair in this stream's check list "
2488 "and the first stream already has valid pairs. Unfreezing immediately.",
2490 priv_conn_check_unfreeze_next (agent, stream);
2493 /* implement the hard upper limit for number of
2494 checks (see sect 5.7.3 ICE ID-19): */
2495 if (agent->compatibility == NICE_COMPATIBILITY_RFC5245) {
2496 if (priv_limit_conn_check_list_size (agent, stream, pair))
2503 NiceCandidateTransport
2504 conn_check_match_transport (NiceCandidateTransport transport)
2506 switch (transport) {
2507 case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
2508 return NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
2510 case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
2511 return NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
2513 case NICE_CANDIDATE_TRANSPORT_TCP_SO:
2514 case NICE_CANDIDATE_TRANSPORT_UDP:
2521 static CandidateCheckPair *priv_conn_check_add_for_candidate_pair_matched (
2522 NiceAgent *agent, guint stream_id, NiceComponent *component,
2523 NiceCandidate *local, NiceCandidate *remote, NiceCheckState initial_state)
2525 CandidateCheckPair *pair;
2527 pair = priv_add_new_check_pair (agent, stream_id, component, local, remote,
2529 if (component->state == NICE_COMPONENT_STATE_CONNECTED ||
2530 component->state == NICE_COMPONENT_STATE_READY) {
2531 agent_signal_component_state_change (agent,
2534 NICE_COMPONENT_STATE_CONNECTED);
2536 agent_signal_component_state_change (agent,
2539 NICE_COMPONENT_STATE_CONNECTING);
2545 gboolean conn_check_add_for_candidate_pair (NiceAgent *agent,
2546 guint stream_id, NiceComponent *component, NiceCandidate *local,
2547 NiceCandidate *remote)
2549 gboolean ret = FALSE;
2551 g_assert (local != NULL);
2552 g_assert (remote != NULL);
2554 /* note: do not create pairs where the local candidate is a srv-reflexive
2555 * or peer-reflexive (ICE 6.1.2.4. "Pruning the pairs" RFC 8445)
2557 if ((agent->compatibility == NICE_COMPATIBILITY_RFC5245 ||
2558 agent->compatibility == NICE_COMPATIBILITY_WLM2009 ||
2559 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
2560 (local->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ||
2561 local->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE)) {
2565 /* note: do not create pairs where local candidate has TCP passive transport
2566 * (ice-tcp-13 6.2. "Forming the Check Lists") */
2567 if (local->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) {
2571 /* note: match pairs only if transport and address family are the same */
2572 if (local->transport == conn_check_match_transport (remote->transport) &&
2573 local->addr.s.addr.sa_family == remote->addr.s.addr.sa_family) {
2574 priv_conn_check_add_for_candidate_pair_matched (agent, stream_id, component,
2575 local, remote, NICE_CHECK_FROZEN);
2583 * Forms new candidate pairs by matching the new remote candidate
2584 * 'remote_cand' with all existing local candidates of 'component'.
2585 * Implements the logic described in ICE sect 5.7.1. "Forming Candidate
2588 * @param agent context
2589 * @param component pointer to the component
2590 * @param remote remote candidate to match with
2592 * @return number of checks added, negative on fatal errors
2594 int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *remote)
2600 g_assert (remote != NULL);
2602 /* note: according to 7.2.1.3, "Learning Peer Reflexive Candidates",
2603 * the agent does not pair this candidate with any local candidates.
2605 if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) &&
2606 remote->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE)
2611 for (i = component->local_candidates; i ; i = i->next) {
2612 NiceCandidate *local = i->data;
2614 if (agent->force_relay && local->type != NICE_CANDIDATE_TYPE_RELAYED)
2617 ret = conn_check_add_for_candidate_pair (agent, stream_id, component, local, remote);
2628 * Forms new candidate pairs by matching the new local candidate
2629 * 'local_cand' with all existing remote candidates of 'component'.
2631 * @param agent context
2632 * @param component pointer to the component
2633 * @param local local candidate to match with
2635 * @return number of checks added, negative on fatal errors
2637 int conn_check_add_for_local_candidate (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *local)
2643 g_assert (local != NULL);
2646 * note: according to 7.1.3.2.1 "Discovering Peer Reflexive
2647 * Candidates", the peer reflexive candidate is not paired
2648 * with other remote candidates
2651 if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) &&
2652 local->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE)
2657 for (i = component->remote_candidates; i ; i = i->next) {
2659 NiceCandidate *remote = i->data;
2660 ret = conn_check_add_for_candidate_pair (agent, stream_id, component, local, remote);
2671 * Frees the CandidateCheckPair structure pointer to
2672 * by 'user data'. Compatible with GDestroyNotify.
2674 static void candidate_check_pair_free (NiceAgent *agent,
2675 CandidateCheckPair *pair)
2677 priv_remove_pair_from_triggered_check_queue (agent, pair);
2678 priv_free_all_stun_transactions (pair, NULL);
2679 g_slice_free (CandidateCheckPair, pair);
2683 * Frees all resources of all connectivity checks.
2685 void conn_check_free (NiceAgent *agent)
2688 for (i = agent->streams; i; i = i->next) {
2689 NiceStream *stream = i->data;
2691 if (stream->conncheck_list) {
2694 nice_debug ("Agent %p, freeing conncheck_list of stream %p", agent,
2696 for (item = stream->conncheck_list; item; item = item->next)
2697 candidate_check_pair_free (agent, item->data);
2698 g_slist_free (stream->conncheck_list);
2699 stream->conncheck_list = NULL;
2703 conn_check_stop (agent);
2707 * Prunes the list of connectivity checks for items related
2708 * to stream 'stream_id'.
2710 * @return TRUE on success, FALSE on a fatal error
2712 void conn_check_prune_stream (NiceAgent *agent, NiceStream *stream)
2715 gboolean keep_going = FALSE;
2717 if (stream->conncheck_list) {
2720 nice_debug ("Agent %p, freeing conncheck_list of stream %p", agent, stream);
2722 for (item = stream->conncheck_list; item; item = item->next)
2723 candidate_check_pair_free (agent, item->data);
2724 g_slist_free (stream->conncheck_list);
2725 stream->conncheck_list = NULL;
2728 for (i = agent->streams; i; i = i->next) {
2729 NiceStream *s = i->data;
2730 if (s->conncheck_list) {
2737 conn_check_stop (agent);
2741 * Fills 'dest' with a username string for use in an outbound connectivity
2742 * checks. No more than 'dest_len' characters (including terminating
2743 * NULL) is ever written to the 'dest'.
2746 size_t priv_gen_username (NiceAgent *agent, guint component_id,
2747 gchar *remote, gchar *local, uint8_t *dest, guint dest_len)
2750 gsize remote_len = strlen (remote);
2751 gsize local_len = strlen (local);
2753 if (remote_len > 0 && local_len > 0) {
2754 if (agent->compatibility == NICE_COMPATIBILITY_RFC5245 &&
2755 dest_len >= remote_len + local_len + 1) {
2756 memcpy (dest, remote, remote_len);
2758 memcpy (dest + len, ":", 1);
2760 memcpy (dest + len, local, local_len);
2762 } else if ((agent->compatibility == NICE_COMPATIBILITY_WLM2009 ||
2763 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
2764 dest_len >= remote_len + local_len + 4 ) {
2765 memcpy (dest, remote, remote_len);
2767 memcpy (dest + len, ":", 1);
2769 memcpy (dest + len, local, local_len);
2772 memset (dest + len, 0, 4 - (len % 4));
2773 len += 4 - (len % 4);
2775 } else if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE &&
2776 dest_len >= remote_len + local_len) {
2777 memcpy (dest, remote, remote_len);
2779 memcpy (dest + len, local, local_len);
2781 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
2782 agent->compatibility == NICE_COMPATIBILITY_OC2007) {
2783 gchar component_str[10];
2784 guchar *local_decoded = NULL;
2785 guchar *remote_decoded = NULL;
2786 gsize local_decoded_len;
2787 gsize remote_decoded_len;
2791 g_snprintf (component_str, sizeof(component_str), "%d", component_id);
2792 local_decoded = g_base64_decode (local, &local_decoded_len);
2793 remote_decoded = g_base64_decode (remote, &remote_decoded_len);
2795 total_len = remote_decoded_len + local_decoded_len + 3 + 2*strlen (component_str);
2796 padding = 4 - (total_len % 4);
2798 if (dest_len >= total_len + padding) {
2799 guchar pad_char[1] = {0};
2802 memcpy (dest, remote_decoded, remote_decoded_len);
2803 len += remote_decoded_len;
2804 memcpy (dest + len, ":", 1);
2806 memcpy (dest + len, component_str, strlen (component_str));
2807 len += strlen (component_str);
2809 memcpy (dest + len, ":", 1);
2812 memcpy (dest + len, local_decoded, local_decoded_len);
2813 len += local_decoded_len;
2814 memcpy (dest + len, ":", 1);
2816 memcpy (dest + len, component_str, strlen (component_str));;
2817 len += strlen (component_str);
2819 for (i = 0; i < padding; i++) {
2820 memcpy (dest + len, pad_char, 1);
2826 g_free (local_decoded);
2827 g_free (remote_decoded);
2835 * Fills 'dest' with a username string for use in an outbound connectivity
2836 * checks. No more than 'dest_len' characters (including terminating
2837 * NULL) is ever written to the 'dest'.
2840 size_t priv_create_username (NiceAgent *agent, NiceStream *stream,
2841 guint component_id, NiceCandidate *remote, NiceCandidate *local,
2842 uint8_t *dest, guint dest_len, gboolean inbound)
2844 gchar *local_username = NULL;
2845 gchar *remote_username = NULL;
2848 if (remote && remote->username) {
2849 remote_username = remote->username;
2852 if (local && local->username) {
2853 local_username = local->username;
2857 if (remote_username == NULL) {
2858 remote_username = stream->remote_ufrag;
2860 if (local_username == NULL) {
2861 local_username = stream->local_ufrag;
2865 if (local_username && remote_username) {
2867 return priv_gen_username (agent, component_id,
2868 local_username, remote_username, dest, dest_len);
2870 return priv_gen_username (agent, component_id,
2871 remote_username, local_username, dest, dest_len);
2879 * Returns a password string for use in an outbound connectivity
2883 size_t priv_get_password (NiceAgent *agent, NiceStream *stream,
2884 NiceCandidate *remote, uint8_t **password)
2886 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE)
2889 if (remote && remote->password) {
2890 *password = (uint8_t *)remote->password;
2891 return strlen (remote->password);
2895 *password = (uint8_t *)stream->remote_password;
2896 return strlen (stream->remote_password);
2902 /* Implement the computation specific in RFC 5245 section 16 */
2904 static unsigned int priv_compute_conncheck_timer (NiceAgent *agent, NiceStream *stream)
2907 guint waiting_and_in_progress = 0;
2909 unsigned int rto = 0;
2911 for (i = stream->conncheck_list; i ; i = i->next) {
2912 CandidateCheckPair *p = i->data;
2913 if (p->state == NICE_CHECK_IN_PROGRESS ||
2914 p->state == NICE_CHECK_WAITING)
2915 waiting_and_in_progress++;
2918 n = priv_number_of_active_check_lists (agent);
2919 rto = agent->timer_ta * n * waiting_and_in_progress;
2921 /* We assume non-reliable streams are RTP, so we use 100 as the max */
2922 nice_debug ("Agent %p : timer set to %dms, "
2923 "waiting+in_progress=%d, nb_active=%d",
2924 agent, agent->reliable ? MAX (rto, 500) : MAX (rto, 100),
2925 waiting_and_in_progress, n);
2926 if (agent->reliable)
2927 return MAX (rto, 500);
2929 return MAX (rto, 100);
2933 * Sends a connectivity check over candidate pair 'pair'.
2935 * @return zero on success, non-zero on error
2937 int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
2940 /* note: following information is supplied:
2941 * - username (for USERNAME attribute)
2942 * - password (for MESSAGE-INTEGRITY)
2943 * - priority (for PRIORITY)
2944 * - ICE-CONTROLLED/ICE-CONTROLLING (for role conflicts)
2945 * - USE-CANDIDATE (if sent by the controlling agent)
2948 uint8_t uname[NICE_STREAM_MAX_UNAME];
2950 NiceComponent *component;
2952 uint8_t *password = NULL;
2954 bool controlling = agent->controlling_mode;
2955 /* XXX: add API to support different nomination modes: */
2956 bool cand_use = controlling;
2958 unsigned int timeout;
2959 StunTransaction *stun;
2961 if (!agent_find_component (agent, pair->stream_id, pair->component_id,
2962 &stream, &component))
2965 uname_len = priv_create_username (agent, stream, pair->component_id,
2966 pair->remote, pair->local, uname, sizeof (uname), FALSE);
2967 password_len = priv_get_password (agent, stream, pair->remote, &password);
2969 if (password != NULL &&
2970 (agent->compatibility == NICE_COMPATIBILITY_MSN ||
2971 agent->compatibility == NICE_COMPATIBILITY_OC2007)) {
2972 password = g_base64_decode ((gchar *) password, &password_len);
2975 if (nice_debug_is_enabled ()) {
2976 gchar tmpbuf1[INET6_ADDRSTRLEN];
2977 gchar tmpbuf2[INET6_ADDRSTRLEN];
2978 nice_address_to_string (&pair->local->addr, tmpbuf1);
2979 nice_address_to_string (&pair->remote->addr, tmpbuf2);
2980 nice_debug ("Agent %p : STUN-CC REQ [%s]:%u --> [%s]:%u, socket=%u, "
2981 "pair=%p (c-id:%u), tie=%llu, username='%.*s' (%" G_GSIZE_FORMAT "), "
2982 "password='%.*s' (%" G_GSIZE_FORMAT "), prio=%08x, %s.", agent,
2983 tmpbuf1, nice_address_get_port (&pair->local->addr),
2984 tmpbuf2, nice_address_get_port (&pair->remote->addr),
2985 pair->sockptr->fileno ? g_socket_get_fd(pair->sockptr->fileno) : -1,
2986 pair, pair->component_id,
2987 (unsigned long long)agent->tie_breaker,
2988 (int) uname_len, uname, uname_len,
2989 (int) password_len, password, password_len,
2990 pair->stun_priority,
2991 controlling ? "controlling" : "controlled");
2994 if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
2995 switch (agent->nomination_mode) {
2996 case NICE_NOMINATION_MODE_REGULAR:
2997 /* We are doing regular nomination, so we set the use-candidate
2998 * attrib, when the controlling agent decided which valid pair to
2999 * resend with this flag in priv_conn_check_tick_stream()
3001 cand_use = pair->use_candidate_on_next_check;
3002 nice_debug ("Agent %p : %s: set cand_use=%d "
3003 "(regular nomination).", agent, G_STRFUNC, cand_use);
3005 case NICE_NOMINATION_MODE_AGGRESSIVE:
3006 /* We are doing aggressive nomination, we set the use-candidate
3007 * attrib in every check we send, when we are the controlling
3008 * agent, RFC 5245, 8.1.1.2
3010 cand_use = controlling;
3011 nice_debug ("Agent %p : %s: set cand_use=%d "
3012 "(aggressive nomination).", agent, G_STRFUNC, cand_use);
3015 /* Nothing to do. */
3018 } else if (cand_use)
3019 pair->nominated = controlling;
3021 if (uname_len == 0) {
3022 nice_debug ("Agent %p: no credentials found, cancelling conncheck", agent);
3026 stun = priv_add_stun_transaction (pair);
3028 buffer_len = stun_usage_ice_conncheck_create (&component->stun_agent,
3029 &stun->message, stun->buffer, sizeof(stun->buffer),
3030 uname, uname_len, password, password_len,
3031 cand_use, controlling, pair->stun_priority,
3033 pair->local->foundation,
3034 agent_to_ice_compatibility (agent));
3036 nice_debug ("Agent %p: conncheck created %zd - %p", agent, buffer_len,
3037 stun->message.buffer);
3039 if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
3040 agent->compatibility == NICE_COMPATIBILITY_OC2007) {
3044 if (buffer_len == 0) {
3045 nice_debug ("Agent %p: buffer is empty, cancelling conncheck", agent);
3046 priv_remove_stun_transaction (pair, stun, component);
3050 if (nice_socket_is_reliable(pair->sockptr)) {
3051 timeout = agent->stun_reliable_timeout;
3052 stun_timer_start_reliable(&stun->timer, timeout);
3054 timeout = priv_compute_conncheck_timer (agent, stream);
3055 stun_timer_start (&stun->timer, timeout, agent->stun_max_retransmissions);
3058 stun->next_tick = g_get_monotonic_time () + timeout * 1000;
3060 /* TCP-ACTIVE candidate must create a new socket before sending
3061 * by connecting to the peer. The new socket is stored in the candidate
3062 * check pair, until we discover a new local peer reflexive */
3063 if (pair->sockptr->fileno == NULL &&
3064 pair->sockptr->type != NICE_SOCKET_TYPE_UDP_TURN &&
3065 pair->local->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) {
3066 NiceStream *stream2 = NULL;
3067 NiceComponent *component2 = NULL;
3068 NiceSocket *new_socket;
3070 if (agent_find_component (agent, pair->stream_id, pair->component_id,
3071 &stream2, &component2)) {
3072 new_socket = nice_tcp_active_socket_connect (pair->sockptr,
3073 &pair->remote->addr);
3075 nice_debug ("Agent %p: add to tcp-act socket %p a new "
3076 "tcp connect socket %p on pair %p in s/c %d/%d",
3077 agent, pair->sockptr, new_socket, pair, stream->id, component->id);
3078 pair->sockptr = new_socket;
3079 _priv_set_socket_tos (agent, pair->sockptr, stream2->tos);
3081 nice_socket_set_writable_callback (pair->sockptr, _tcp_sock_is_writable,
3084 nice_component_attach_socket (component2, new_socket);
3088 /* send the conncheck */
3089 agent_socket_send (pair->sockptr, &pair->remote->addr,
3090 buffer_len, (gchar *)stun->buffer);
3092 if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2)
3093 ms_ice2_legacy_conncheck_send (&stun->message, pair->sockptr,
3094 &pair->remote->addr);
3100 * Implemented the pruning steps described in ICE sect 8.1.2
3101 * "Updating States" (ID-19) after a pair has been nominated.
3103 * @see conn_check_update_check_list_state_failed_components()
3105 static guint priv_prune_pending_checks (NiceAgent *agent, NiceStream *stream, NiceComponent *component)
3109 guint in_progress = 0;
3110 gchar prio[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE];
3112 nice_debug ("Agent %p: Pruning pending checks for s%d/c%d",
3113 agent, stream->id, component->id);
3115 /* Called when we have at least one selected pair */
3116 priority = component->selected_pair.priority;
3117 g_assert (priority > 0);
3119 nice_candidate_pair_priority_to_string (priority, prio);
3120 nice_debug ("Agent %p : selected pair priority is %s", agent, prio);
3122 i = stream->conncheck_list;
3124 CandidateCheckPair *p = i->data;
3125 GSList *next = i->next;
3127 if (p->component_id != component->id) {
3132 /* step: cancel all FROZEN and WAITING pairs for the component */
3133 if (p->state == NICE_CHECK_FROZEN || p->state == NICE_CHECK_WAITING) {
3134 nice_debug ("Agent %p : pair %p removed.", agent, p);
3135 candidate_check_pair_free (agent, p);
3136 stream->conncheck_list = g_slist_delete_link(stream->conncheck_list, i);
3139 /* note: a SHOULD level req. in ICE 8.1.2. "Updating States" (ID-19) */
3140 else if (p->state == NICE_CHECK_IN_PROGRESS) {
3141 if (p->priority < priority) {
3142 priv_remove_pair_from_triggered_check_queue (agent, p);
3143 if (p->retransmit && p->stun_transactions) {
3144 p->retransmit = FALSE;
3145 nice_debug ("Agent %p : pair %p will not be retransmitted.",
3147 } else if (p->retransmit) {
3148 /* Pair in-progress, but stun request not yet sent */
3149 nice_debug ("Agent %p : pair %p removed.", agent, p);
3150 candidate_check_pair_free (agent, p);
3151 stream->conncheck_list = g_slist_delete_link(stream->conncheck_list,
3155 /* We must keep the higher priority pairs running because if a udp
3156 * packet was lost, we might end up using a bad candidate */
3157 nice_candidate_pair_priority_to_string (p->priority, prio);
3158 nice_debug ("Agent %p : pair %p kept IN_PROGRESS because priority "
3159 "%s is higher than priority of best nominated pair.", agent, p, prio);
3160 /* We may also have to enable the retransmit flag of pairs with
3161 * a higher priority than the first nominated pair
3163 if (!p->retransmit && p->stun_transactions) {
3164 p->retransmit = TRUE;
3165 nice_debug ("Agent %p : pair %p will be retransmitted.", agent, p);
3170 /* A triggered check on a failed pair will depend on the retransmit
3171 * flag, so on the relative priority of this pair and the nominated
3174 else if (p->state == NICE_CHECK_FAILED)
3175 p->retransmit = (p->priority > priority ? TRUE : FALSE);
3183 * Schedules a triggered check after a successfully inbound
3184 * connectivity check. Implements ICE sect 7.2.1.4 "Triggered Checks" (ID-19).
3186 * @param agent self pointer
3187 * @param component the check is related to
3188 * @param local_socket socket from which the inbound check was received
3189 * @param remote_cand remote candidate from which the inbound check was sent
3191 static gboolean priv_schedule_triggered_check (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceSocket *local_socket, NiceCandidate *remote_cand)
3194 NiceCandidate *local = NULL;
3195 CandidateCheckPair *p;
3197 g_assert (remote_cand != NULL);
3199 nice_debug ("Agent %p : scheduling triggered check with socket=%p "
3200 "and remote cand=%p.", agent, local_socket, remote_cand);
3202 for (i = stream->conncheck_list; i ; i = i->next) {
3204 if (p->component_id == component->id &&
3205 p->remote == remote_cand &&
3206 p->sockptr == local_socket) {
3207 /* If we match with a peer-reflexive discovered pair, we
3208 * use the parent succeeded pair instead */
3210 if (p->succeeded_pair != NULL) {
3211 g_assert_cmpint (p->state, ==, NICE_CHECK_DISCOVERED);
3212 p = p->succeeded_pair;
3215 nice_debug ("Agent %p : Found a matching pair %p (%s) (%s) ...",
3216 agent, p, p->foundation, priv_state_to_string (p->state));
3219 case NICE_CHECK_WAITING:
3220 case NICE_CHECK_FROZEN:
3221 nice_debug ("Agent %p : pair %p added for a triggered check.",
3223 priv_add_pair_to_triggered_check_queue (agent, p);
3225 case NICE_CHECK_IN_PROGRESS:
3226 /* note: according to ICE SPEC sect 7.2.1.4 "Triggered Checks"
3227 * we cancel the in-progress transaction, and after the
3228 * retransmission timeout, we create a new connectivity check
3229 * for that pair. The controlling role of this new check may
3230 * be different from the role of this cancelled check.
3232 * note: the flag retransmit unset means that
3233 * another pair, with a higher priority is already nominated,
3234 * so there's no reason to recheck this pair, since it can in
3235 * no way replace the nominated one.
3237 if (!nice_socket_is_reliable (p->sockptr) && p->retransmit) {
3238 nice_debug ("Agent %p : pair %p added for a triggered check.",
3240 priv_add_pair_to_triggered_check_queue (agent, p);
3243 case NICE_CHECK_FAILED:
3244 if (p->retransmit) {
3245 nice_debug ("Agent %p : pair %p added for a triggered check.",
3247 priv_add_pair_to_triggered_check_queue (agent, p);
3248 /* If the component for this pair is in failed state, move it
3249 * back to connecting, and reinitiate the timers
3251 if (component->state == NICE_COMPONENT_STATE_FAILED) {
3252 agent_signal_component_state_change (agent, stream->id,
3253 component->id, NICE_COMPONENT_STATE_CONNECTING);
3254 conn_check_schedule_next (agent);
3258 case NICE_CHECK_SUCCEEDED:
3259 nice_debug ("Agent %p : nothing to do for pair %p.", agent, p);
3260 /* note: this is a bit unsure corner-case -- let's do the
3261 same state update as for processing responses to our own checks */
3262 /* note: this update is required by the trickle test, to
3263 * ensure the transition ready -> connected -> ready, because
3264 * an incoming stun request generates a discovered peer reflexive,
3265 * that causes the ready -> connected transition.
3267 conn_check_update_check_list_state_for_ready (agent, stream,
3274 /* note: the spec says the we SHOULD retransmit in-progress
3275 * checks immediately, but we won't do that now */
3281 for (i = component->local_candidates; i ; i = i->next) {
3283 if (local->sockptr == local_socket)
3288 nice_debug ("Agent %p : Adding a triggered check to conn.check list (local=%p).", agent, local);
3289 p = priv_conn_check_add_for_candidate_pair_matched (agent, stream->id,
3290 component, local, remote_cand, NICE_CHECK_WAITING);
3292 priv_add_pair_to_triggered_check_queue (agent, p);
3296 nice_debug ("Agent %p : Didn't find a matching pair for triggered check (remote-cand=%p).", agent, remote_cand);
3303 * Sends a reply to an successfully received STUN connectivity
3304 * check request. Implements parts of the ICE spec section 7.2 (STUN
3305 * Server Procedures).
3307 * @param agent context pointer
3308 * @param stream which stream (of the agent)
3309 * @param component which component (of the stream)
3310 * @param rcand remote candidate from which the request came, if NULL,
3311 * the response is sent immediately but no other processing is done
3312 * @param toaddr address to which reply is sent
3313 * @param socket the socket over which the request came
3314 * @param rbuf_len length of STUN message to send
3315 * @param msg the STUN message to send
3316 * @param use_candidate whether the request had USE_CANDIDATE attribute
3318 * @pre (rcand == NULL || nice_address_equal(rcand->addr, toaddr) == TRUE)
3320 static void priv_reply_to_conn_check (NiceAgent *agent, NiceStream *stream,
3321 NiceComponent *component, NiceCandidate *lcand, NiceCandidate *rcand,
3322 const NiceAddress *toaddr, NiceSocket *sockptr, size_t rbuf_len,
3323 StunMessage *msg, gboolean use_candidate)
3325 g_assert (rcand == NULL || nice_address_equal(&rcand->addr, toaddr) == TRUE);
3327 if (nice_debug_is_enabled ()) {
3328 gchar tmpbuf[INET6_ADDRSTRLEN];
3329 nice_address_to_string (toaddr, tmpbuf);
3330 nice_debug ("Agent %p : STUN-CC RESP to '%s:%u', socket=%u, len=%u, cand=%p (c-id:%u), use-cand=%d.", agent,
3332 nice_address_get_port (toaddr),
3333 sockptr->fileno ? g_socket_get_fd(sockptr->fileno) : -1,
3335 rcand, component->id,
3336 (int)use_candidate);
3339 agent_socket_send (sockptr, toaddr, rbuf_len, (const gchar*)msg->buffer);
3340 if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
3341 ms_ice2_legacy_conncheck_send(msg, sockptr, toaddr);
3344 /* We react to this stun request when we have the remote credentials.
3345 * When credentials are not yet known, this request is stored
3346 * in incoming_checks for later processing when returning from this
3349 if (rcand && stream->remote_ufrag[0]) {
3350 priv_schedule_triggered_check (agent, stream, component, sockptr, rcand);
3352 priv_mark_pair_nominated (agent, stream, component, lcand, rcand);
3357 * Stores information of an incoming STUN connectivity check
3358 * for later use. This is only needed when a check is received
3359 * before we get information about the remote candidates (via
3360 * SDP or other signaling means).
3362 * @return non-zero on error, zero on success
3364 static int priv_store_pending_check (NiceAgent *agent, NiceComponent *component,
3365 const NiceAddress *from, NiceSocket *sockptr, uint8_t *username,
3366 uint16_t username_len, uint32_t priority, gboolean use_candidate)
3368 IncomingCheck *icheck;
3369 nice_debug ("Agent %p : Storing pending check.", agent);
3371 if (g_queue_get_length (&component->incoming_checks) >=
3372 NICE_AGENT_MAX_REMOTE_CANDIDATES) {
3373 nice_debug ("Agent %p : WARN: unable to store information for early incoming check.", agent);
3377 icheck = g_slice_new0 (IncomingCheck);
3378 g_queue_push_tail (&component->incoming_checks, icheck);
3379 icheck->from = *from;
3380 icheck->local_socket = sockptr;
3381 icheck->priority = priority;
3382 icheck->use_candidate = use_candidate;
3383 icheck->username_len = username_len;
3384 icheck->username = NULL;
3385 if (username_len > 0)
3386 icheck->username = g_memdup (username, username_len);
3392 * Adds a new pair, discovered from an incoming STUN response, to
3393 * the connectivity check list.
3395 * @return created pair, or NULL on fatal (memory allocation) errors
3397 static CandidateCheckPair *priv_add_peer_reflexive_pair (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *local_cand, CandidateCheckPair *parent_pair)
3399 CandidateCheckPair *pair = g_slice_new0 (CandidateCheckPair);
3400 NiceStream *stream = agent_find_stream (agent, stream_id);
3402 pair->stream_id = stream_id;
3403 pair->component_id = component->id;;
3404 pair->local = local_cand;
3405 pair->remote = parent_pair->remote;
3406 pair->sockptr = local_cand->sockptr;
3407 parent_pair->discovered_pair = pair;
3408 pair->succeeded_pair = parent_pair;
3409 nice_debug ("Agent %p : creating a new pair", agent);
3410 SET_PAIR_STATE (agent, pair, NICE_CHECK_DISCOVERED);
3412 gchar tmpbuf1[INET6_ADDRSTRLEN];
3413 gchar tmpbuf2[INET6_ADDRSTRLEN];
3414 nice_address_to_string (&pair->local->addr, tmpbuf1);
3415 nice_address_to_string (&pair->remote->addr, tmpbuf2);
3416 nice_debug ("Agent %p : new pair %p : [%s]:%u --> [%s]:%u", agent, pair,
3417 tmpbuf1, nice_address_get_port (&pair->local->addr),
3418 tmpbuf2, nice_address_get_port (&pair->remote->addr));
3420 g_snprintf (pair->foundation, NICE_CANDIDATE_PAIR_MAX_FOUNDATION, "%s:%s",
3421 local_cand->foundation, parent_pair->remote->foundation);
3423 if (agent->controlling_mode == TRUE)
3424 pair->priority = nice_candidate_pair_priority (pair->local->priority,
3425 pair->remote->priority);
3427 pair->priority = nice_candidate_pair_priority (pair->remote->priority,
3428 pair->local->priority);
3429 pair->nominated = parent_pair->nominated;
3430 /* the peer-reflexive priority used in stun request is copied from
3431 * the parent succeeded pair. This value is not required for discovered
3432 * pair, that won't emit stun requests themselves, but may be used when
3433 * such pair becomes the selected pair, and when keepalive stun are emitted,
3434 * using the sockptr and stun_priority values from the succeeded pair.
3436 pair->stun_priority = parent_pair->stun_priority;
3437 nice_debug ("Agent %p : added a new peer-discovered pair %p with "
3438 "foundation '%s' and transport %s:%s to stream %u component %u",
3439 agent, pair, pair->foundation,
3440 priv_candidate_transport_to_string (pair->local->transport),
3441 priv_candidate_transport_to_string (pair->remote->transport),
3442 stream_id, component->id);
3444 stream->conncheck_list = g_slist_insert_sorted (stream->conncheck_list, pair,
3445 (GCompareFunc)conn_check_compare);
3451 * Recalculates priorities of all candidate pairs. This
3452 * is required after a conflict in ICE roles.
3454 void recalculate_pair_priorities (NiceAgent *agent)
3458 for (i = agent->streams; i; i = i->next) {
3459 NiceStream *stream = i->data;
3460 for (j = stream->conncheck_list; j; j = j->next) {
3461 CandidateCheckPair *p = j->data;
3462 p->priority = agent_candidate_pair_priority (agent, p->local, p->remote);
3464 stream->conncheck_list = g_slist_sort (stream->conncheck_list,
3465 (GCompareFunc)conn_check_compare);
3470 * Change the agent role if different from 'control'. Can be
3471 * initiated both by handling of incoming connectivity checks,
3472 * and by processing the responses to checks sent by us.
3474 static void priv_check_for_role_conflict (NiceAgent *agent, gboolean control)
3476 /* role conflict, change mode; wait for a new conn. check */
3477 if (control != agent->controlling_mode) {
3478 nice_debug ("Agent %p : Role conflict, changing agent role to \"%s\".",
3479 agent, control ? "controlling" : "controlled");
3480 agent->controlling_mode = control;
3481 /* the pair priorities depend on the roles, so recalculation
3483 recalculate_pair_priorities (agent);
3486 nice_debug ("Agent %p : Role conflict, staying with role \"%s\".",
3487 agent, control ? "controlling" : "controlled");
3491 * Checks whether the mapped address in connectivity check response
3492 * matches any of the known local candidates. If not, apply the
3493 * mechanism for "Discovering Peer Reflexive Candidates" ICE ID-19)
3495 * @param agent context pointer
3496 * @param stream which stream (of the agent)
3497 * @param component which component (of the stream)
3498 * @param p the connectivity check pair for which we got a response
3499 * @param socketptr socket used to send the reply
3500 * @param mapped_sockaddr mapped address in the response
3502 * @return pointer to a candidate pair, found in conncheck list or newly created
3504 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)
3506 CandidateCheckPair *new_pair = NULL;
3509 NiceCandidate *local_cand = NULL;
3511 nice_address_set_from_sockaddr (&mapped, mapped_sockaddr);
3513 for (i = component->local_candidates; i; i = i->next) {
3514 NiceCandidate *cand = i->data;
3516 if (nice_address_equal (&mapped, &cand->addr) &&
3517 local_candidate_and_socket_compatible (agent, cand, sockptr)) {
3523 /* The mapped address allows to look for a previously discovered
3524 * peer reflexive local candidate, and its related pair. This
3525 * new_pair will be marked 'Valid', while the pair 'p' of the
3526 * initial stun request will be marked 'Succeeded'
3528 * In the case of a tcp-act/tcp-pass pair 'p', where the local
3529 * candidate is of type tcp-act, and its port number is zero, a
3530 * conncheck on this pair *always* leads to the creation of a
3531 * discovered peer-reflexive tcp-act local candidate.
3533 for (i = stream->conncheck_list; i; i = i->next) {
3534 CandidateCheckPair *pair = i->data;
3535 if (local_cand == pair->local && remote_candidate == pair->remote) {
3542 /* note: when new_pair is distinct from p, it means new_pair is a
3543 * previously discovered peer-reflexive candidate pair, so we don't
3544 * set the valid flag on p in this case, because the valid flag is
3545 * already set on the discovered pair.
3549 SET_PAIR_STATE (agent, p, NICE_CHECK_SUCCEEDED);
3550 priv_remove_pair_from_triggered_check_queue (agent, p);
3551 priv_free_all_stun_transactions (p, component);
3552 nice_component_add_valid_candidate (agent, component, remote_candidate);
3555 if (local_cand == NULL && !agent->force_relay) {
3556 /* step: find a new local candidate, see RFC 5245 7.1.3.2.1.
3557 * "Discovering Peer Reflexive Candidates"
3559 * The priority equal to the value of the PRIORITY attribute
3560 * in the Binding request is taken from the "parent" pair p
3562 local_cand = discovery_add_peer_reflexive_candidate (agent,
3570 nice_debug ("Agent %p : added a new peer-reflexive local candidate %p "
3571 "with transport %s", agent, local_cand,
3572 priv_candidate_transport_to_string (local_cand->transport));
3575 /* step: add a new discovered pair (see RFC 5245 7.1.3.2.2
3576 "Constructing a Valid Pair") */
3578 new_pair = priv_add_peer_reflexive_pair (agent, stream->id, component,
3580 /* note: this is same as "adding to VALID LIST" in the spec
3583 new_pair->valid = TRUE;
3584 /* step: The agent sets the state of the pair that *generated* the check to
3585 * Succeeded, RFC 5245, 7.1.3.2.3, "Updating Pair States"
3587 SET_PAIR_STATE (agent, p, NICE_CHECK_SUCCEEDED);
3588 priv_remove_pair_from_triggered_check_queue (agent, p);
3589 priv_free_all_stun_transactions (p, component);
3592 if (new_pair && new_pair->valid)
3593 nice_component_add_valid_candidate (agent, component, remote_candidate);
3600 * Tries to match STUN reply in 'buf' to an existing STUN connectivity
3601 * check transaction. If found, the reply is processed. Implements
3602 * section 7.1.2 "Processing the Response" of ICE spec (ID-19).
3604 * @return TRUE if a matching transaction is found
3606 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)
3609 struct sockaddr_storage storage;
3610 struct sockaddr addr;
3612 socklen_t socklen = sizeof (sockaddr);
3615 StunUsageIceReturn res;
3616 StunTransactionId discovery_id;
3617 StunTransactionId response_id;
3618 stun_message_id (resp, response_id);
3620 for (i = stream->conncheck_list; i; i = i->next) {
3621 CandidateCheckPair *p = i->data;
3623 for (j = p->stun_transactions, k = 0; j; j = j->next, k++) {
3624 StunTransaction *stun = j->data;
3626 stun_message_id (&stun->message, discovery_id);
3628 if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)))
3631 res = stun_usage_ice_conncheck_process (resp,
3632 &sockaddr.storage, &socklen,
3633 agent_to_ice_compatibility (agent));
3634 nice_debug ("Agent %p : stun_bind_process/conncheck for %p: "
3635 "%s,res=%s,stun#=%d.",
3637 agent->controlling_mode ? "controlling" : "controlled",
3638 priv_ice_return_to_string (res), k);
3640 if (res == STUN_USAGE_ICE_RETURN_SUCCESS ||
3641 res == STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS) {
3642 /* case: found a matching connectivity check request */
3644 CandidateCheckPair *ok_pair = NULL;
3646 nice_debug ("Agent %p : pair %p MATCHED.", agent, p);
3647 priv_remove_stun_transaction (p, stun, component);
3649 /* step: verify that response came from the same IP address we
3650 * sent the original request to (see 7.1.2.1. "Failure
3652 if (nice_address_equal (from, &p->remote->addr) == FALSE) {
3653 candidate_check_pair_fail (stream, agent, p);
3654 if (nice_debug_is_enabled ()) {
3655 gchar tmpbuf[INET6_ADDRSTRLEN];
3656 gchar tmpbuf2[INET6_ADDRSTRLEN];
3657 nice_debug ("Agent %p : pair %p FAILED"
3658 " (mismatch of source address).", agent, p);
3659 nice_address_to_string (&p->remote->addr, tmpbuf);
3660 nice_address_to_string (from, tmpbuf2);
3661 nice_debug ("Agent %p : '%s:%u' != '%s:%u'", agent,
3662 tmpbuf, nice_address_get_port (&p->remote->addr),
3663 tmpbuf2, nice_address_get_port (from));
3668 if (remote_candidate == NULL) {
3669 candidate_check_pair_fail (stream, agent, p);
3670 if (nice_debug_is_enabled ()) {
3671 nice_debug ("Agent %p : pair %p FAILED "
3672 "(got a matching pair without a known remote candidate).", agent, p);
3677 /* note: CONNECTED but not yet READY, see docs */
3679 /* step: handle the possible case of a peer-reflexive
3680 * candidate where the mapped-address in response does
3681 * not match any local candidate, see 7.1.2.2.1
3682 * "Discovering Peer Reflexive Candidates" ICE ID-19) */
3684 if (res == STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS) {
3685 nice_debug ("Agent %p : Mapped address not found", agent);
3686 SET_PAIR_STATE (agent, p, NICE_CHECK_SUCCEEDED);
3688 nice_component_add_valid_candidate (agent, component, p->remote);
3690 ok_pair = priv_process_response_check_for_reflexive (agent,
3691 stream, component, p, sockptr, &sockaddr.addr,
3692 local_candidate, remote_candidate);
3694 /* note: The success of this check might also
3695 * cause the state of other checks to change as well, ICE
3698 priv_conn_check_unfreeze_related (agent, stream, p);
3700 /* Note: this assignment helps to reduce the numbers of cases
3701 * to be tested. If ok_pair and p refer to distinct pairs, it
3702 * means that ok_pair is a discovered peer reflexive one,
3703 * caused by the check made on pair p. In that case, the
3704 * flags to be tested are on p, but the nominated flag will be
3705 * set on ok_pair. When there's no discovered pair, p and
3706 * ok_pair refer to the same pair.
3707 * To summarize : p is a SUCCEEDED pair, ok_pair is a
3708 * DISCOVERED, VALID, and eventually NOMINATED pair.
3713 /* step: updating nominated flag (ICE 7.1.2.2.4 "Updating the
3714 Nominated Flag" (ID-19) */
3715 if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
3716 nice_debug ("Agent %p : Updating nominated flag (%s): "
3717 "ok_pair=%p (%d/%d) p=%p (%d/%d) (ucnc/mnora)",
3718 agent, p->local->transport == NICE_CANDIDATE_TRANSPORT_UDP ?
3720 ok_pair, ok_pair->use_candidate_on_next_check,
3721 ok_pair->mark_nominated_on_response_arrival,
3722 p, p->use_candidate_on_next_check,
3723 p->mark_nominated_on_response_arrival);
3725 if (agent->controlling_mode) {
3726 switch (agent->nomination_mode) {
3727 case NICE_NOMINATION_MODE_REGULAR:
3728 if (p->use_candidate_on_next_check) {
3729 nice_debug ("Agent %p : marking pair %p (%s) as nominated "
3730 "(regular nomination, controlling, "
3731 "use_cand_on_next_check=1).",
3732 agent, ok_pair, ok_pair->foundation);
3733 ok_pair->nominated = TRUE;
3736 case NICE_NOMINATION_MODE_AGGRESSIVE:
3737 if (!p->nominated) {
3738 nice_debug ("Agent %p : marking pair %p (%s) as nominated "
3739 "(aggressive nomination, controlling).",
3740 agent, ok_pair, ok_pair->foundation);
3741 ok_pair->nominated = TRUE;
3749 if (p->mark_nominated_on_response_arrival) {
3750 nice_debug ("Agent %p : marking pair %p (%s) as nominated "
3751 "(%s nomination, controlled, mark_on_response=1).",
3752 agent, ok_pair, ok_pair->foundation,
3753 agent->nomination_mode == NICE_NOMINATION_MODE_AGGRESSIVE ?
3754 "aggressive" : "regular");
3755 ok_pair->nominated = TRUE;
3760 if (ok_pair->nominated == TRUE) {
3761 conn_check_update_selected_pair (agent, component, ok_pair);
3762 priv_print_conn_check_lists (agent, G_STRFUNC,
3763 ", got a nominated pair");
3765 /* Do not step down to CONNECTED if we're already at state READY*/
3766 if (component->state != NICE_COMPONENT_STATE_READY)
3767 /* step: notify the client of a new component state (must be done
3768 * before the possible check list state update step */
3769 agent_signal_component_state_change (agent,
3770 stream->id, component->id, NICE_COMPONENT_STATE_CONNECTED);
3773 /* step: update pair states (ICE 7.1.2.2.3 "Updating pair
3774 states" and 8.1.2 "Updating States", ID-19) */
3775 conn_check_update_check_list_state_for_ready (agent, stream, component);
3776 } else if (res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT) {
3778 gboolean controlled_mode;
3780 if (!p->retransmit) {
3781 nice_debug ("Agent %p : Role conflict with pair %p, not restarting",
3786 /* case: role conflict error, need to restart with new role */
3787 nice_debug ("Agent %p : Role conflict with pair %p, restarting",
3790 /* note: this res value indicates that the role of the peer
3791 * agent has not changed after the tie-breaker comparison, so
3792 * this is our role that must change. see ICE sect. 7.1.3.1
3793 * "Failure Cases". Our role might already have changed due to
3794 * an earlier incoming request, but if not, change role now.
3796 * Sect. 7.1.3.1 is not clear on this point, but we choose to
3797 * put the candidate pair in the triggered check list even
3798 * when the agent did not switch its role. The reason for this
3799 * interpretation is that the reception of the stun reply, even
3800 * an error reply, is a good sign that this pair will be
3801 * valid, if we retry the check after the role of both peers
3804 controlled_mode = (stun_message_find64 (&stun->message,
3805 STUN_ATTRIBUTE_ICE_CONTROLLED, &tie) ==
3806 STUN_MESSAGE_RETURN_SUCCESS);
3808 priv_check_for_role_conflict (agent, controlled_mode);
3809 priv_remove_stun_transaction (p, stun, component);
3810 priv_add_pair_to_triggered_check_queue (agent, p);
3812 /* case: STUN error, the check STUN context was freed */
3813 candidate_check_pair_fail (stream, agent, p);
3823 * Tries to match STUN reply in 'buf' to an existing STUN discovery
3824 * transaction. If found, a reply is sent.
3826 * @return TRUE if a matching transaction is found
3828 static gboolean priv_map_reply_to_discovery_request (NiceAgent *agent, StunMessage *resp)
3831 struct sockaddr_storage storage;
3832 struct sockaddr addr;
3834 socklen_t socklen = sizeof (sockaddr);
3837 struct sockaddr_storage storage;
3838 struct sockaddr addr;
3840 socklen_t alternatelen = sizeof (sockaddr);
3843 StunUsageBindReturn res;
3844 gboolean trans_found = FALSE;
3845 StunTransactionId discovery_id;
3846 StunTransactionId response_id;
3847 stun_message_id (resp, response_id);
3849 for (i = agent->discovery_list; i && trans_found != TRUE; i = i->next) {
3850 CandidateDiscovery *d = i->data;
3852 if (d->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE &&
3853 d->stun_message.buffer) {
3854 stun_message_id (&d->stun_message, discovery_id);
3856 if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)) == 0) {
3857 res = stun_usage_bind_process (resp, &sockaddr.addr,
3858 &socklen, &alternate.addr, &alternatelen);
3859 nice_debug ("Agent %p : stun_bind_process/disc for %p res %d.",
3860 agent, d, (int)res);
3862 if (res == STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER) {
3863 /* handle alternate server */
3864 NiceAddress niceaddr;
3865 nice_address_set_from_sockaddr (&niceaddr, &alternate.addr);
3866 d->server = niceaddr;
3869 agent->discovery_unsched_items++;
3870 } else if (res == STUN_USAGE_BIND_RETURN_SUCCESS) {
3871 /* case: successful binding discovery, create a new local candidate */
3873 if (!agent->force_relay) {
3874 NiceAddress niceaddr;
3876 nice_address_set_from_sockaddr (&niceaddr, &sockaddr.addr);
3877 discovery_add_server_reflexive_candidate (
3882 NICE_CANDIDATE_TRANSPORT_UDP,
3885 if (agent->use_ice_tcp)
3886 discovery_discover_tcp_server_reflexive_candidates (
3893 d->stun_message.buffer = NULL;
3894 d->stun_message.buffer_len = 0;
3897 } else if (res == STUN_USAGE_BIND_RETURN_ERROR) {
3898 /* case: STUN error, the check STUN context was freed */
3899 d->stun_message.buffer = NULL;
3900 d->stun_message.buffer_len = 0;
3912 priv_calc_turn_timeout (guint lifetime)
3915 return lifetime - 60;
3917 return lifetime / 2;
3920 static CandidateRefresh *
3921 priv_add_new_turn_refresh (NiceAgent *agent, CandidateDiscovery *cdisco,
3922 NiceCandidate *relay_cand, guint lifetime)
3924 CandidateRefresh *cand;
3926 cand = g_slice_new0 (CandidateRefresh);
3927 agent->refresh_list = g_slist_append (agent->refresh_list, cand);
3929 cand->candidate = relay_cand;
3930 cand->nicesock = cdisco->nicesock;
3931 cand->server = cdisco->server;
3932 cand->stream_id = cdisco->stream_id;
3933 cand->component_id = cdisco->component_id;
3934 memcpy (&cand->stun_agent, &cdisco->stun_agent, sizeof(StunAgent));
3936 /* Use previous stun response for authentication credentials */
3937 if (cdisco->stun_resp_msg.buffer != NULL) {
3938 memcpy(cand->stun_resp_buffer, cdisco->stun_resp_buffer,
3939 sizeof(cand->stun_resp_buffer));
3940 memcpy(&cand->stun_resp_msg, &cdisco->stun_resp_msg, sizeof(StunMessage));
3941 cand->stun_resp_msg.buffer = cand->stun_resp_buffer;
3942 cand->stun_resp_msg.agent = NULL;
3943 cand->stun_resp_msg.key = NULL;
3946 nice_debug ("Agent %p : Adding new refresh candidate %p with timeout %d",
3947 agent, cand, priv_calc_turn_timeout (lifetime));
3948 /* step: also start the refresh timer */
3949 /* refresh should be sent 1 minute before it expires */
3950 agent_timeout_add_seconds_with_context (agent, &cand->timer_source,
3951 "Candidate TURN refresh",
3952 priv_calc_turn_timeout (lifetime),
3953 priv_turn_allocate_refresh_tick_agent_locked, cand);
3955 nice_debug ("timer source is : %p", cand->timer_source);
3960 static void priv_handle_turn_alternate_server (NiceAgent *agent,
3961 CandidateDiscovery *disco, NiceAddress server, NiceAddress alternate)
3963 /* We need to cancel and reset all candidate discovery turn for the same
3964 stream and type if there is an alternate server. Otherwise, we might end up
3965 with two relay components on different servers, creating candidates with
3966 unique foundations that only contain one component.
3970 for (i = agent->discovery_list; i; i = i->next) {
3971 CandidateDiscovery *d = i->data;
3974 d->type == disco->type &&
3975 d->stream_id == disco->stream_id &&
3976 d->turn->type == disco->turn->type &&
3977 nice_address_equal (&d->server, &server)) {
3978 gchar ip[INET6_ADDRSTRLEN];
3979 // Cancel the pending request to avoid a race condition with another
3980 // component responding with another altenrate-server
3981 d->stun_message.buffer = NULL;
3982 d->stun_message.buffer_len = 0;
3984 nice_address_to_string (&server, ip);
3985 nice_debug ("Agent %p : Cancelling and setting alternate server %s for "
3986 "CandidateDiscovery %p", agent, ip, d);
3987 d->server = alternate;
3988 d->turn->server = alternate;
3990 agent->discovery_unsched_items++;
3996 * Tries to match STUN reply in 'buf' to an existing STUN discovery
3997 * transaction. If found, a reply is sent.
3999 * @return TRUE if a matching transaction is found
4001 static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *resp)
4004 struct sockaddr_storage storage;
4005 struct sockaddr addr;
4007 socklen_t socklen = sizeof (sockaddr);
4010 struct sockaddr_storage storage;
4011 struct sockaddr addr;
4013 socklen_t alternatelen = sizeof (alternate);
4016 struct sockaddr_storage storage;
4017 struct sockaddr addr;
4019 socklen_t relayaddrlen = sizeof (relayaddr);
4024 StunUsageTurnReturn res;
4025 gboolean trans_found = FALSE;
4026 StunTransactionId discovery_id;
4027 StunTransactionId response_id;
4028 stun_message_id (resp, response_id);
4030 for (i = agent->discovery_list; i && trans_found != TRUE; i = i->next) {
4031 CandidateDiscovery *d = i->data;
4033 if (d->type == NICE_CANDIDATE_TYPE_RELAYED &&
4034 d->stun_message.buffer) {
4035 stun_message_id (&d->stun_message, discovery_id);
4037 if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)) == 0) {
4038 res = stun_usage_turn_process (resp,
4039 &relayaddr.storage, &relayaddrlen,
4040 &sockaddr.storage, &socklen,
4041 &alternate.storage, &alternatelen,
4042 &bandwidth, &lifetime, agent_to_turn_compatibility (agent));
4043 nice_debug ("Agent %p : stun_turn_process/disc for %p res %d.",
4044 agent, d, (int)res);
4046 if (res == STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER) {
4049 /* handle alternate server */
4050 nice_address_set_from_sockaddr (&addr, &alternate.addr);
4051 priv_handle_turn_alternate_server (agent, d, d->server, addr);
4053 } else if (res == STUN_USAGE_TURN_RETURN_RELAY_SUCCESS ||
4054 res == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS) {
4055 /* case: successful allocate, create a new local candidate */
4056 NiceAddress niceaddr;
4057 NiceCandidate *relay_cand;
4059 nice_address_set_from_sockaddr (&niceaddr, &relayaddr.addr);
4061 if (res == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS) {
4062 NiceAddress mappedniceaddr;
4064 /* We also received our mapped address */
4065 nice_address_set_from_sockaddr (&mappedniceaddr, &sockaddr.addr);
4067 /* TCP or TLS TURNS means the server-reflexive address was
4068 * on a TCP connection, which cannot be used for server-reflexive
4069 * discovery of candidates.
4071 if (d->turn->type == NICE_RELAY_TYPE_TURN_UDP &&
4072 !agent->force_relay) {
4073 discovery_add_server_reflexive_candidate (
4078 NICE_CANDIDATE_TRANSPORT_UDP,
4082 if (agent->use_ice_tcp) {
4083 if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4084 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
4085 !nice_address_equal_no_port (&niceaddr, &d->turn->server)) {
4086 nice_debug("TURN port got allocated on an alternate server, "
4087 "ignoring bogus srflx address");
4089 discovery_discover_tcp_server_reflexive_candidates (
4099 if (nice_socket_is_reliable (d->nicesock)) {
4100 relay_cand = discovery_add_relay_candidate (
4105 NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE,
4110 if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4111 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
4112 nice_udp_turn_socket_set_ms_realm(relay_cand->sockptr,
4114 nice_udp_turn_socket_set_ms_connection_id(relay_cand->sockptr,
4117 priv_add_new_turn_refresh (agent, d, relay_cand, lifetime);
4121 relay_cand = discovery_add_relay_candidate (
4126 NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE,
4130 relay_cand = discovery_add_relay_candidate (
4135 NICE_CANDIDATE_TRANSPORT_UDP,
4141 if (d->stun_resp_msg.buffer)
4142 nice_udp_turn_socket_cache_realm_nonce (relay_cand->sockptr,
4144 if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4145 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
4146 /* These data are needed on TURN socket when sending requests,
4147 * but never reach nice_turn_socket_parse_recv() where it could
4148 * be read directly, as the socket does not exist when allocate
4149 * response arrives to _nice_agent_recv(). We must set them right
4150 * after socket gets created in discovery_add_relay_candidate(),
4151 * so we are doing it here. */
4152 nice_udp_turn_socket_set_ms_realm(relay_cand->sockptr,
4154 nice_udp_turn_socket_set_ms_connection_id(relay_cand->sockptr,
4157 priv_add_new_turn_refresh (agent, d, relay_cand, lifetime);
4160 /* In case a new candidate has been added */
4161 conn_check_schedule_next (agent);
4164 d->stun_message.buffer = NULL;
4165 d->stun_message.buffer_len = 0;
4168 } else if (res == STUN_USAGE_TURN_RETURN_ERROR) {
4170 uint8_t *sent_realm = NULL;
4171 uint8_t *recv_realm = NULL;
4172 uint16_t sent_realm_len = 0;
4173 uint16_t recv_realm_len = 0;
4175 sent_realm = (uint8_t *) stun_message_find (&d->stun_message,
4176 STUN_ATTRIBUTE_REALM, &sent_realm_len);
4177 recv_realm = (uint8_t *) stun_message_find (resp,
4178 STUN_ATTRIBUTE_REALM, &recv_realm_len);
4180 if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4181 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
4182 alternatelen != sizeof(alternate)) {
4185 nice_address_set_from_sockaddr (&addr, &alternate.addr);
4187 if (!nice_address_equal (&addr, &d->server)) {
4188 priv_handle_turn_alternate_server (agent, d, d->server, addr);
4191 /* check for unauthorized error response */
4192 if ((agent->compatibility == NICE_COMPATIBILITY_RFC5245 ||
4193 agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4194 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
4195 stun_message_get_class (resp) == STUN_ERROR &&
4196 stun_message_find_error (resp, &code) ==
4197 STUN_MESSAGE_RETURN_SUCCESS &&
4198 recv_realm != NULL && recv_realm_len > 0) {
4200 if (code == STUN_ERROR_STALE_NONCE ||
4201 (code == STUN_ERROR_UNAUTHORIZED &&
4202 !(recv_realm_len == sent_realm_len &&
4203 sent_realm != NULL &&
4204 memcmp (sent_realm, recv_realm, sent_realm_len) == 0))) {
4205 d->stun_resp_msg = *resp;
4206 memcpy (d->stun_resp_buffer, resp->buffer,
4207 stun_message_length (resp));
4208 d->stun_resp_msg.buffer = d->stun_resp_buffer;
4209 d->stun_resp_msg.buffer_len = sizeof(d->stun_resp_buffer);
4211 agent->discovery_unsched_items++;
4213 /* case: a real unauthorized error */
4214 d->stun_message.buffer = NULL;
4215 d->stun_message.buffer_len = 0;
4219 /* case: STUN error, the check STUN context was freed */
4220 d->stun_message.buffer = NULL;
4221 d->stun_message.buffer_len = 0;
4235 * Tries to match STUN reply in 'buf' to an existing STUN discovery
4236 * transaction. If found, a reply is sent.
4238 * @return TRUE if a matching transaction is found
4240 static gboolean priv_map_reply_to_relay_refresh (NiceAgent *agent, StunMessage *resp)
4244 StunUsageTurnReturn res;
4245 gboolean trans_found = FALSE;
4246 StunTransactionId refresh_id;
4247 StunTransactionId response_id;
4248 stun_message_id (resp, response_id);
4250 for (i = agent->refresh_list; i && trans_found != TRUE;) {
4251 CandidateRefresh *cand = i->data;
4252 GSList *next = i->next;
4254 if (!cand->disposing && cand->stun_message.buffer) {
4255 stun_message_id (&cand->stun_message, refresh_id);
4257 if (memcmp (refresh_id, response_id, sizeof(StunTransactionId)) == 0) {
4258 res = stun_usage_turn_refresh_process (resp,
4259 &lifetime, agent_to_turn_compatibility (agent));
4260 nice_debug ("Agent %p : stun_turn_refresh_process for %p res %d with lifetime %u.",
4261 agent, cand, (int)res, lifetime);
4262 if (res == STUN_USAGE_TURN_RETURN_RELAY_SUCCESS) {
4263 /* refresh should be sent 1 minute before it expires */
4264 agent_timeout_add_seconds_with_context (agent,
4265 &cand->timer_source,
4266 "Candidate TURN refresh", priv_calc_turn_timeout (lifetime),
4267 priv_turn_allocate_refresh_tick_agent_locked, cand);
4269 g_source_destroy (cand->tick_source);
4270 g_source_unref (cand->tick_source);
4271 cand->tick_source = NULL;
4273 } else if (res == STUN_USAGE_TURN_RETURN_ERROR) {
4275 uint8_t *sent_realm = NULL;
4276 uint8_t *recv_realm = NULL;
4277 uint16_t sent_realm_len = 0;
4278 uint16_t recv_realm_len = 0;
4280 sent_realm = (uint8_t *) stun_message_find (&cand->stun_message,
4281 STUN_ATTRIBUTE_REALM, &sent_realm_len);
4282 recv_realm = (uint8_t *) stun_message_find (resp,
4283 STUN_ATTRIBUTE_REALM, &recv_realm_len);
4285 /* check for unauthorized error response */
4286 if (agent->compatibility == NICE_COMPATIBILITY_RFC5245 &&
4287 stun_message_get_class (resp) == STUN_ERROR &&
4288 stun_message_find_error (resp, &code) ==
4289 STUN_MESSAGE_RETURN_SUCCESS &&
4290 recv_realm != NULL && recv_realm_len > 0) {
4292 if (code == STUN_ERROR_STALE_NONCE ||
4293 (code == STUN_ERROR_UNAUTHORIZED &&
4294 !(recv_realm_len == sent_realm_len &&
4295 sent_realm != NULL &&
4296 memcmp (sent_realm, recv_realm, sent_realm_len) == 0))) {
4297 cand->stun_resp_msg = *resp;
4298 memcpy (cand->stun_resp_buffer, resp->buffer,
4299 stun_message_length (resp));
4300 cand->stun_resp_msg.buffer = cand->stun_resp_buffer;
4301 cand->stun_resp_msg.buffer_len = sizeof(cand->stun_resp_buffer);
4302 priv_turn_allocate_refresh_tick_unlocked (agent, cand);
4304 /* case: a real unauthorized error */
4305 refresh_free (agent, cand);
4308 /* case: STUN error, the check STUN context was freed */
4309 refresh_free (agent, cand);
4321 static gboolean priv_map_reply_to_relay_remove (NiceAgent *agent,
4324 StunTransactionId response_id;
4327 stun_message_id (resp, response_id);
4329 for (i = agent->refresh_list; i; i = i->next) {
4330 CandidateRefresh *cand = i->data;
4331 StunTransactionId request_id;
4332 StunUsageTurnReturn res;
4335 if (!cand->disposing || !cand->stun_message.buffer) {
4339 stun_message_id (&cand->stun_message, request_id);
4341 if (memcmp (request_id, response_id, sizeof(StunTransactionId)) == 0) {
4342 res = stun_usage_turn_refresh_process (resp, &lifetime,
4343 agent_to_turn_compatibility (agent));
4345 nice_debug ("Agent %p : priv_map_reply_to_relay_remove for %p res %d "
4346 "with lifetime %u.", agent, cand, res, lifetime);
4348 if (res != STUN_USAGE_TURN_RETURN_INVALID) {
4349 refresh_free (agent, cand);
4358 static gboolean priv_map_reply_to_keepalive_conncheck (NiceAgent *agent,
4359 NiceComponent *component, StunMessage *resp)
4361 StunTransactionId conncheck_id;
4362 StunTransactionId response_id;
4363 stun_message_id (resp, response_id);
4365 if (component->selected_pair.keepalive.stun_message.buffer) {
4366 stun_message_id (&component->selected_pair.keepalive.stun_message,
4368 if (memcmp (conncheck_id, response_id, sizeof(StunTransactionId)) == 0) {
4369 nice_debug ("Agent %p : Keepalive for selected pair received.",
4371 if (component->selected_pair.keepalive.tick_source) {
4372 g_source_destroy (component->selected_pair.keepalive.tick_source);
4373 g_source_unref (component->selected_pair.keepalive.tick_source);
4374 component->selected_pair.keepalive.tick_source = NULL;
4376 component->selected_pair.keepalive.stun_message.buffer = NULL;
4388 NiceComponent *component;
4390 } conncheck_validater_data;
4392 static bool conncheck_stun_validater (StunAgent *agent,
4393 StunMessage *message, uint8_t *username, uint16_t username_len,
4394 uint8_t **password, size_t *password_len, void *user_data)
4396 conncheck_validater_data *data = (conncheck_validater_data*) user_data;
4398 gchar *ufrag = NULL;
4401 gboolean msn_msoc_nice_compatibility =
4402 data->agent->compatibility == NICE_COMPATIBILITY_MSN ||
4403 data->agent->compatibility == NICE_COMPATIBILITY_OC2007;
4405 if (data->agent->compatibility == NICE_COMPATIBILITY_OC2007 &&
4406 stun_message_get_class (message) == STUN_RESPONSE)
4407 i = data->component->remote_candidates;
4409 i = data->component->local_candidates;
4411 for (; i; i = i->next) {
4412 NiceCandidate *cand = i->data;
4416 ufrag = cand->username;
4418 ufrag = data->stream->local_ufrag;
4419 ufrag_len = ufrag? strlen (ufrag) : 0;
4421 if (ufrag && msn_msoc_nice_compatibility)
4422 ufrag = (gchar *)g_base64_decode (ufrag, &ufrag_len);
4427 stun_debug ("Comparing username/ufrag of len %d and %" G_GSIZE_FORMAT ", equal=%d",
4428 username_len, ufrag_len, username_len >= ufrag_len ?
4429 memcmp (username, ufrag, ufrag_len) : 0);
4430 stun_debug_bytes (" username: ", username, username_len);
4431 stun_debug_bytes (" ufrag: ", ufrag, ufrag_len);
4432 if (ufrag_len > 0 && username_len >= ufrag_len &&
4433 memcmp (username, ufrag, ufrag_len) == 0) {
4437 pass = cand->password;
4438 else if (data->stream && data->stream->local_password[0])
4439 pass = data->stream->local_password;
4442 *password = (uint8_t *) pass;
4443 *password_len = strlen (pass);
4445 if (msn_msoc_nice_compatibility) {
4448 data->password = g_base64_decode (pass, &pass_len);
4449 *password = data->password;
4450 *password_len = pass_len;
4454 if (msn_msoc_nice_compatibility)
4457 stun_debug ("Found valid username, returning password: '%s'", *password);
4461 if (msn_msoc_nice_compatibility)
4469 * handle RENOMINATION stun attribute
4470 * @return TRUE if nomination changed. FALSE otherwise
4472 static gboolean conn_check_handle_renomination (NiceAgent *agent, NiceStream *stream,
4473 NiceComponent *component, StunMessage *req,
4474 NiceCandidate *remote_candidate, NiceCandidate *local_candidate)
4477 if (!agent->controlling_mode && NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) &&
4478 agent->support_renomination && remote_candidate && local_candidate)
4480 uint32_t nom_value = 0;
4481 uint16_t nom_len = 0;
4482 const void *value = stun_message_find (req, STUN_ATTRIBUTE_NOMINATION, &nom_len);
4487 memcpy (&nom_value, value, 4);
4488 nom_value = ntohl (nom_value);
4490 nice_debug ("Agent %p : received NOMINATION attr with incorrect octet length %u, expected 4 bytes",
4495 if (nice_debug_is_enabled ()) {
4496 gchar remote_str[INET6_ADDRSTRLEN];
4497 nice_address_to_string(&remote_candidate->addr, remote_str);
4498 nice_debug ("Agent %p : received NOMINATION attr for remote candidate [%s]:%u, value is %u",
4499 agent, remote_str, nice_address_get_port (&remote_candidate->addr), nom_value);
4503 * If another pair is SELECTED, change this pair's priority to be greater than
4504 * selected pair's priority so this pair gets SELECTED!
4506 if (component->selected_pair.priority &&
4507 component->selected_pair.remote && component->selected_pair.remote != remote_candidate &&
4508 component->selected_pair.local && component->selected_pair.local != local_candidate) {
4509 for (lst = stream->conncheck_list; lst; lst = lst->next) {
4510 CandidateCheckPair *pair = lst->data;
4511 if (pair->local == local_candidate && pair->remote == remote_candidate) {
4513 pair->priority = component->selected_pair.priority + 1;
4519 priv_mark_pair_nominated (agent, stream, component, local_candidate, remote_candidate);
4526 * Processing an incoming STUN message.
4528 * @param agent self pointer
4529 * @param stream stream the packet is related to
4530 * @param component component the packet is related to
4531 * @param nicesock socket from which the packet was received
4532 * @param from address of the sender
4533 * @param buf message contents
4534 * @param buf message length
4536 * @pre contents of 'buf' is a STUN message
4538 * @return XXX (what FALSE means exactly?)
4540 gboolean conn_check_handle_inbound_stun (NiceAgent *agent, NiceStream *stream,
4541 NiceComponent *component, NiceSocket *nicesock, const NiceAddress *from,
4542 gchar *buf, guint len)
4545 struct sockaddr_storage storage;
4546 struct sockaddr addr;
4548 uint8_t rbuf[MAX_STUN_DATAGRAM_PAYLOAD];
4550 size_t rbuf_len = sizeof (rbuf);
4551 bool control = agent->controlling_mode;
4552 uint8_t uname[NICE_STREAM_MAX_UNAME];
4555 uint16_t username_len;
4558 StunValidationStatus valid;
4559 conncheck_validater_data validater_data = {agent, stream, component, NULL};
4561 NiceCandidate *remote_candidate = NULL;
4562 NiceCandidate *remote_candidate2 = NULL;
4563 NiceCandidate *local_candidate = NULL;
4564 gboolean discovery_msg = FALSE;
4566 nice_address_copy_to_sockaddr (from, &sockaddr.addr);
4568 /* note: contents of 'buf' already validated, so it is
4569 * a valid and fully received STUN message */
4571 if (nice_debug_is_enabled ()) {
4572 gchar tmpbuf[INET6_ADDRSTRLEN];
4573 nice_address_to_string (from, tmpbuf);
4574 nice_debug ("Agent %p: inbound STUN packet for %u/%u (stream/component) from [%s]:%u (%u octets) :",
4575 agent, stream->id, component->id, tmpbuf, nice_address_get_port (from), len);
4578 /* note: ICE 7.2. "STUN Server Procedures" (ID-19) */
4580 valid = stun_agent_validate (&component->stun_agent, &req,
4581 (uint8_t *) buf, len, conncheck_stun_validater, &validater_data);
4583 /* Check for discovery candidates stun agents */
4584 if (valid == STUN_VALIDATION_BAD_REQUEST ||
4585 valid == STUN_VALIDATION_UNMATCHED_RESPONSE) {
4586 for (i = agent->discovery_list; i; i = i->next) {
4587 CandidateDiscovery *d = i->data;
4588 if (d->stream_id == stream->id && d->component_id == component->id &&
4589 d->nicesock == nicesock) {
4590 valid = stun_agent_validate (&d->stun_agent, &req,
4591 (uint8_t *) buf, len, conncheck_stun_validater, &validater_data);
4593 if (valid == STUN_VALIDATION_UNMATCHED_RESPONSE)
4596 discovery_msg = TRUE;
4601 /* Check for relay refresh stun agents */
4602 if (valid == STUN_VALIDATION_BAD_REQUEST ||
4603 valid == STUN_VALIDATION_UNMATCHED_RESPONSE) {
4604 for (i = agent->refresh_list; i; i = i->next) {
4605 CandidateRefresh *r = i->data;
4607 nice_debug_verbose ("Comparing r.sid=%u to sid=%u, r.cid=%u to cid=%u and %p and %p to %p",
4608 r->stream_id, stream->id, r->component_id, component->id, r->nicesock,
4609 r->candidate->sockptr, nicesock);
4611 if (r->stream_id == stream->id && r->component_id == component->id &&
4612 (r->nicesock == nicesock || r->candidate->sockptr == nicesock)) {
4613 valid = stun_agent_validate (&r->stun_agent, &req,
4614 (uint8_t *) buf, len, conncheck_stun_validater, &validater_data);
4615 nice_debug ("Validating gave %d", valid);
4616 if (valid == STUN_VALIDATION_UNMATCHED_RESPONSE)
4618 discovery_msg = TRUE;
4624 g_free (validater_data.password);
4626 if (valid == STUN_VALIDATION_NOT_STUN ||
4627 valid == STUN_VALIDATION_INCOMPLETE_STUN ||
4628 valid == STUN_VALIDATION_BAD_REQUEST)
4630 nice_debug ("Agent %p : Incorrectly multiplexed STUN message ignored.",
4635 if (valid == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE) {
4636 nice_debug ("Agent %p : Unknown mandatory attributes in message.", agent);
4638 if (agent->compatibility != NICE_COMPATIBILITY_MSN &&
4639 agent->compatibility != NICE_COMPATIBILITY_OC2007) {
4640 rbuf_len = stun_agent_build_unknown_attributes_error (&component->stun_agent,
4641 &msg, rbuf, rbuf_len, &req);
4643 agent_socket_send (nicesock, from, rbuf_len, (const gchar*)rbuf);
4648 if (valid == STUN_VALIDATION_UNAUTHORIZED) {
4649 nice_debug ("Agent %p : Integrity check failed.", agent);
4651 if (stun_agent_init_error (&component->stun_agent, &msg, rbuf, rbuf_len,
4652 &req, STUN_ERROR_UNAUTHORIZED)) {
4653 rbuf_len = stun_agent_finish_message (&component->stun_agent, &msg, NULL, 0);
4654 if (rbuf_len > 0 && agent->compatibility != NICE_COMPATIBILITY_MSN &&
4655 agent->compatibility != NICE_COMPATIBILITY_OC2007)
4656 agent_socket_send (nicesock, from, rbuf_len, (const gchar*)rbuf);
4660 if (valid == STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST) {
4661 nice_debug ("Agent %p : Integrity check failed - bad request.", agent);
4662 if (stun_agent_init_error (&component->stun_agent, &msg, rbuf, rbuf_len,
4663 &req, STUN_ERROR_BAD_REQUEST)) {
4664 rbuf_len = stun_agent_finish_message (&component->stun_agent, &msg, NULL, 0);
4665 if (rbuf_len > 0 && agent->compatibility != NICE_COMPATIBILITY_MSN &&
4666 agent->compatibility != NICE_COMPATIBILITY_OC2007)
4667 agent_socket_send (nicesock, from, rbuf_len, (const gchar*)rbuf);
4672 username = (uint8_t *) stun_message_find (&req, STUN_ATTRIBUTE_USERNAME,
4675 for (i = component->local_candidates; i; i = i->next) {
4676 NiceCandidate *cand = i->data;
4679 if (cand->type == NICE_CANDIDATE_TYPE_RELAYED)
4682 addr = &cand->base_addr;
4684 if (nice_address_equal (&nicesock->addr, addr) &&
4685 local_candidate_and_socket_compatible (agent, cand, nicesock)) {
4686 local_candidate = cand;
4691 for (i = component->remote_candidates; i; i = i->next) {
4692 NiceCandidate *cand = i->data;
4693 if (nice_address_equal (from, &cand->addr) &&
4694 remote_candidate_and_socket_compatible (agent, local_candidate,
4696 remote_candidate = cand;
4701 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE ||
4702 agent->compatibility == NICE_COMPATIBILITY_MSN ||
4703 agent->compatibility == NICE_COMPATIBILITY_OC2007) {
4704 /* We need to find which local candidate was used */
4705 for (i = component->remote_candidates;
4706 i != NULL && remote_candidate2 == NULL; i = i->next) {
4707 for (j = component->local_candidates; j; j = j->next) {
4708 gboolean inbound = TRUE;
4709 NiceCandidate *rcand = i->data;
4710 NiceCandidate *lcand = j->data;
4712 /* If we receive a response, then the username is local:remote */
4713 if (agent->compatibility != NICE_COMPATIBILITY_MSN) {
4714 if (stun_message_get_class (&req) == STUN_REQUEST ||
4715 stun_message_get_class (&req) == STUN_INDICATION) {
4722 uname_len = priv_create_username (agent, stream,
4723 component->id, rcand, lcand,
4724 uname, sizeof (uname), inbound);
4728 stun_debug ("Comparing usernames of size %d and %d: %d",
4729 username_len, uname_len, username && uname_len == username_len &&
4730 memcmp (username, uname, uname_len) == 0);
4731 stun_debug_bytes (" First username: ", username,
4732 username ? username_len : 0);
4733 stun_debug_bytes (" Second uname: ", uname, uname_len);
4736 uname_len == username_len &&
4737 memcmp (uname, username, username_len) == 0) {
4738 local_candidate = lcand;
4739 remote_candidate2 = rcand;
4746 if (component->remote_candidates &&
4747 agent->compatibility == NICE_COMPATIBILITY_GOOGLE &&
4748 local_candidate == NULL &&
4749 discovery_msg == FALSE) {
4750 /* if we couldn't match the username and the stun agent has
4751 IGNORE_CREDENTIALS then we have an integrity check failing.
4752 This could happen with the race condition of receiving connchecks
4753 before the remote candidates are added. Just drop the message, and let
4754 the retransmissions make it work. */
4755 nice_debug ("Agent %p : Username check failed.", agent);
4759 /* This is most likely caused by a second response to a request which
4760 * already has received a valid reply.
4762 if (valid == STUN_VALIDATION_UNMATCHED_RESPONSE) {
4763 nice_debug ("Agent %p : Valid STUN response for which we don't have a request, ignoring", agent);
4767 if (valid != STUN_VALIDATION_SUCCESS) {
4768 nice_debug ("Agent %p : STUN message is unsuccessful %d, ignoring", agent, valid);
4773 if (stun_message_get_class (&req) == STUN_REQUEST) {
4774 if ( agent->compatibility == NICE_COMPATIBILITY_MSN
4775 || agent->compatibility == NICE_COMPATIBILITY_OC2007) {
4776 if (local_candidate && remote_candidate2) {
4779 if (agent->compatibility == NICE_COMPATIBILITY_MSN) {
4780 username = (uint8_t *) stun_message_find (&req,
4781 STUN_ATTRIBUTE_USERNAME, &username_len);
4782 uname_len = priv_create_username (agent, stream,
4783 component->id, remote_candidate2, local_candidate,
4784 uname, sizeof (uname), FALSE);
4785 memcpy (username, uname, MIN (uname_len, username_len));
4787 req.key = g_base64_decode ((gchar *) remote_candidate2->password,
4789 req.key_len = key_len;
4790 } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007) {
4791 req.key = g_base64_decode ((gchar *) local_candidate->password,
4793 req.key_len = key_len;
4796 nice_debug ("Agent %p : received MSN incoming check from unknown remote candidate. "
4797 "Ignoring request", agent);
4802 rbuf_len = sizeof (rbuf);
4803 res = stun_usage_ice_conncheck_create_reply (&component->stun_agent, &req,
4804 &msg, rbuf, &rbuf_len, &sockaddr.storage, sizeof (sockaddr),
4805 &control, agent->tie_breaker,
4806 agent_to_ice_compatibility (agent));
4808 if ( agent->compatibility == NICE_COMPATIBILITY_MSN
4809 || agent->compatibility == NICE_COMPATIBILITY_OC2007) {
4813 if (res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT)
4814 priv_check_for_role_conflict (agent, control);
4816 if (res == STUN_USAGE_ICE_RETURN_SUCCESS ||
4817 res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT) {
4818 /* case 1: valid incoming request, send a reply/error */
4819 bool use_candidate =
4820 stun_usage_ice_conncheck_use_candidate (&req);
4821 uint32_t priority = stun_usage_ice_conncheck_priority (&req);
4823 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE ||
4824 agent->compatibility == NICE_COMPATIBILITY_MSN ||
4825 agent->compatibility == NICE_COMPATIBILITY_OC2007)
4826 use_candidate = TRUE;
4828 if (stream->initial_binding_request_received != TRUE)
4829 agent_signal_initial_binding_request_received (agent, stream);
4831 if (remote_candidate == NULL) {
4832 nice_debug ("Agent %p : No matching remote candidate for incoming "
4833 "check -> peer-reflexive candidate.", agent);
4834 remote_candidate = discovery_learn_remote_peer_reflexive_candidate (
4835 agent, stream, component, priority, from, nicesock,
4837 remote_candidate2 ? remote_candidate2 : remote_candidate);
4838 if(remote_candidate && stream->remote_ufrag[0]) {
4839 if (local_candidate &&
4840 local_candidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) {
4841 CandidateCheckPair *pair;
4843 pair = priv_conn_check_add_for_candidate_pair_matched (agent,
4844 stream->id, component, local_candidate, remote_candidate,
4845 NICE_CHECK_SUCCEEDED);
4850 conn_check_add_for_candidate (agent, stream->id, component, remote_candidate);
4854 nice_component_add_valid_candidate (agent, component, remote_candidate);
4856 priv_reply_to_conn_check (agent, stream, component, local_candidate,
4857 remote_candidate, from, nicesock, rbuf_len, &msg, use_candidate);
4859 if (stream->remote_ufrag[0] == 0) {
4860 /* case: We've got a valid binding request to a local candidate
4861 * but we do not yet know remote credentials.
4862 * As per sect 7.2 of ICE (ID-19), we send a reply
4863 * immediately but postpone all other processing until
4864 * we get information about the remote candidates */
4866 /* step: send a reply immediately but postpone other processing */
4867 priv_store_pending_check (agent, component, from, nicesock,
4868 username, username_len, priority, use_candidate);
4869 priv_print_conn_check_lists (agent, G_STRFUNC, ", icheck stored");
4872 nice_debug ("Agent %p : Invalid STUN packet, ignoring... %s",
4873 agent, strerror(errno));
4877 /* case 2: not a new request, might be a reply... */
4878 gboolean trans_found = FALSE;
4880 /* note: ICE sect 7.1.2. "Processing the Response" (ID-19) */
4882 /* step: let's try to match the response to an existing check context */
4883 if (trans_found != TRUE)
4884 trans_found = priv_map_reply_to_conn_check_request (agent, stream,
4885 component, nicesock, from, local_candidate, remote_candidate, &req);
4887 /* step: let's try to match the response to an existing discovery */
4888 if (trans_found != TRUE)
4889 trans_found = priv_map_reply_to_discovery_request (agent, &req);
4891 /* step: let's try to match the response to an existing turn allocate */
4892 if (trans_found != TRUE)
4893 trans_found = priv_map_reply_to_relay_request (agent, &req);
4895 /* step: let's try to match the response to an existing turn refresh */
4896 if (trans_found != TRUE)
4897 trans_found = priv_map_reply_to_relay_refresh (agent, &req);
4899 if (trans_found != TRUE)
4900 trans_found = priv_map_reply_to_relay_remove (agent, &req);
4902 /* step: let's try to match the response to an existing keepalive conncheck */
4903 if (trans_found != TRUE)
4904 trans_found = priv_map_reply_to_keepalive_conncheck (agent, component,
4907 if (trans_found != TRUE)
4908 nice_debug ("Agent %p : Unable to match to an existing transaction, "
4909 "probably a keepalive.", agent);
4912 /* RENOMINATION attribute support */
4913 conn_check_handle_renomination(agent, stream, component, &req, remote_candidate, local_candidate);
4918 /* Remove all pointers to the given @sock from the connection checking process.
4919 * These are entirely NiceCandidates pointed to from various places. */
4921 conn_check_prune_socket (NiceAgent *agent, NiceStream *stream, NiceComponent *component,
4926 if (component->selected_pair.local &&
4927 component->selected_pair.local->sockptr == sock &&
4928 component->state == NICE_COMPONENT_STATE_READY) {
4929 nice_debug ("Agent %p: Selected pair socket %p has been destroyed, "
4930 "declaring failed", agent, sock);
4931 agent_signal_component_state_change (agent,
4932 stream->id, component->id, NICE_COMPONENT_STATE_FAILED);
4935 /* Prune from the candidate check pairs. */
4936 for (l = stream->conncheck_list; l != NULL;) {
4937 CandidateCheckPair *p = l->data;
4938 GSList *next = l->next;
4940 if ((p->local != NULL && p->local->sockptr == sock) ||
4941 (p->remote != NULL && p->remote->sockptr == sock) ||
4942 (p->sockptr == sock)) {
4943 nice_debug ("Agent %p : Retransmissions failed, giving up on pair %p",
4945 candidate_check_pair_fail (stream, agent, p);
4946 candidate_check_pair_free (agent, p);
4947 stream->conncheck_list = g_slist_delete_link (stream->conncheck_list, l);