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->local->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE &&
3207 p->sockptr == local_socket) ||
3208 (p->local->transport != NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE &&
3209 p->local->sockptr == local_socket))) {
3210 /* We don't check for p->sockptr because in the case of
3211 * tcp-active we don't want to retrigger a check on a pair that
3212 * was FAILED when a peer-reflexive pair was created */
3214 if (p->succeeded_pair != NULL) {
3215 g_assert_cmpint (p->state, ==, NICE_CHECK_DISCOVERED);
3216 p = p->succeeded_pair;
3219 nice_debug ("Agent %p : Found a matching pair %p (%s) (%s) ...",
3220 agent, p, p->foundation, priv_state_to_string (p->state));
3223 case NICE_CHECK_WAITING:
3224 case NICE_CHECK_FROZEN:
3225 nice_debug ("Agent %p : pair %p added for a triggered check.",
3227 priv_add_pair_to_triggered_check_queue (agent, p);
3229 case NICE_CHECK_IN_PROGRESS:
3230 /* note: according to ICE SPEC sect 7.2.1.4 "Triggered Checks"
3231 * we cancel the in-progress transaction, and after the
3232 * retransmission timeout, we create a new connectivity check
3233 * for that pair. The controlling role of this new check may
3234 * be different from the role of this cancelled check.
3236 * note: the flag retransmit unset means that
3237 * another pair, with a higher priority is already nominated,
3238 * so there's no reason to recheck this pair, since it can in
3239 * no way replace the nominated one.
3241 if (!nice_socket_is_reliable (p->sockptr) && p->retransmit) {
3242 nice_debug ("Agent %p : pair %p added for a triggered check.",
3244 priv_add_pair_to_triggered_check_queue (agent, p);
3247 case NICE_CHECK_FAILED:
3248 if (p->retransmit) {
3249 nice_debug ("Agent %p : pair %p added for a triggered check.",
3251 priv_add_pair_to_triggered_check_queue (agent, p);
3252 /* If the component for this pair is in failed state, move it
3253 * back to connecting, and reinitiate the timers
3255 if (component->state == NICE_COMPONENT_STATE_FAILED) {
3256 agent_signal_component_state_change (agent, stream->id,
3257 component->id, NICE_COMPONENT_STATE_CONNECTING);
3258 conn_check_schedule_next (agent);
3262 case NICE_CHECK_SUCCEEDED:
3263 nice_debug ("Agent %p : nothing to do for pair %p.", agent, p);
3264 /* note: this is a bit unsure corner-case -- let's do the
3265 same state update as for processing responses to our own checks */
3266 /* note: this update is required by the trickle test, to
3267 * ensure the transition ready -> connected -> ready, because
3268 * an incoming stun request generates a discovered peer reflexive,
3269 * that causes the ready -> connected transition.
3271 conn_check_update_check_list_state_for_ready (agent, stream,
3278 /* note: the spec says the we SHOULD retransmit in-progress
3279 * checks immediately, but we won't do that now */
3285 for (i = component->local_candidates; i ; i = i->next) {
3287 if (local->sockptr == local_socket)
3292 nice_debug ("Agent %p : Adding a triggered check to conn.check list (local=%p).", agent, local);
3293 p = priv_conn_check_add_for_candidate_pair_matched (agent, stream->id,
3294 component, local, remote_cand, NICE_CHECK_WAITING);
3296 priv_add_pair_to_triggered_check_queue (agent, p);
3300 nice_debug ("Agent %p : Didn't find a matching pair for triggered check (remote-cand=%p).", agent, remote_cand);
3307 * Sends a reply to an successfully received STUN connectivity
3308 * check request. Implements parts of the ICE spec section 7.2 (STUN
3309 * Server Procedures).
3311 * @param agent context pointer
3312 * @param stream which stream (of the agent)
3313 * @param component which component (of the stream)
3314 * @param rcand remote candidate from which the request came, if NULL,
3315 * the response is sent immediately but no other processing is done
3316 * @param toaddr address to which reply is sent
3317 * @param socket the socket over which the request came
3318 * @param rbuf_len length of STUN message to send
3319 * @param msg the STUN message to send
3320 * @param use_candidate whether the request had USE_CANDIDATE attribute
3322 * @pre (rcand == NULL || nice_address_equal(rcand->addr, toaddr) == TRUE)
3324 static void priv_reply_to_conn_check (NiceAgent *agent, NiceStream *stream,
3325 NiceComponent *component, NiceCandidate *lcand, NiceCandidate *rcand,
3326 const NiceAddress *toaddr, NiceSocket *sockptr, size_t rbuf_len,
3327 StunMessage *msg, gboolean use_candidate)
3329 g_assert (rcand == NULL || nice_address_equal(&rcand->addr, toaddr) == TRUE);
3331 if (nice_debug_is_enabled ()) {
3332 gchar tmpbuf[INET6_ADDRSTRLEN];
3333 nice_address_to_string (toaddr, tmpbuf);
3334 nice_debug ("Agent %p : STUN-CC RESP to '%s:%u', socket=%u, len=%u, cand=%p (c-id:%u), use-cand=%d.", agent,
3336 nice_address_get_port (toaddr),
3337 sockptr->fileno ? g_socket_get_fd(sockptr->fileno) : -1,
3339 rcand, component->id,
3340 (int)use_candidate);
3343 agent_socket_send (sockptr, toaddr, rbuf_len, (const gchar*)msg->buffer);
3344 if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
3345 ms_ice2_legacy_conncheck_send(msg, sockptr, toaddr);
3348 /* We react to this stun request when we have the remote credentials.
3349 * When credentials are not yet known, this request is stored
3350 * in incoming_checks for later processing when returning from this
3353 if (rcand && stream->remote_ufrag[0]) {
3354 priv_schedule_triggered_check (agent, stream, component, sockptr, rcand);
3356 priv_mark_pair_nominated (agent, stream, component, lcand, rcand);
3361 * Stores information of an incoming STUN connectivity check
3362 * for later use. This is only needed when a check is received
3363 * before we get information about the remote candidates (via
3364 * SDP or other signaling means).
3366 * @return non-zero on error, zero on success
3368 static int priv_store_pending_check (NiceAgent *agent, NiceComponent *component,
3369 const NiceAddress *from, NiceSocket *sockptr, uint8_t *username,
3370 uint16_t username_len, uint32_t priority, gboolean use_candidate)
3372 IncomingCheck *icheck;
3373 nice_debug ("Agent %p : Storing pending check.", agent);
3375 if (g_queue_get_length (&component->incoming_checks) >=
3376 NICE_AGENT_MAX_REMOTE_CANDIDATES) {
3377 nice_debug ("Agent %p : WARN: unable to store information for early incoming check.", agent);
3381 icheck = g_slice_new0 (IncomingCheck);
3382 g_queue_push_tail (&component->incoming_checks, icheck);
3383 icheck->from = *from;
3384 icheck->local_socket = sockptr;
3385 icheck->priority = priority;
3386 icheck->use_candidate = use_candidate;
3387 icheck->username_len = username_len;
3388 icheck->username = NULL;
3389 if (username_len > 0)
3390 icheck->username = g_memdup (username, username_len);
3396 * Adds a new pair, discovered from an incoming STUN response, to
3397 * the connectivity check list.
3399 * @return created pair, or NULL on fatal (memory allocation) errors
3401 static CandidateCheckPair *priv_add_peer_reflexive_pair (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *local_cand, CandidateCheckPair *parent_pair)
3403 CandidateCheckPair *pair = g_slice_new0 (CandidateCheckPair);
3404 NiceStream *stream = agent_find_stream (agent, stream_id);
3406 pair->stream_id = stream_id;
3407 pair->component_id = component->id;;
3408 pair->local = local_cand;
3409 pair->remote = parent_pair->remote;
3410 pair->sockptr = local_cand->sockptr;
3411 parent_pair->discovered_pair = pair;
3412 pair->succeeded_pair = parent_pair;
3413 nice_debug ("Agent %p : creating a new pair", agent);
3414 SET_PAIR_STATE (agent, pair, NICE_CHECK_DISCOVERED);
3416 gchar tmpbuf1[INET6_ADDRSTRLEN];
3417 gchar tmpbuf2[INET6_ADDRSTRLEN];
3418 nice_address_to_string (&pair->local->addr, tmpbuf1);
3419 nice_address_to_string (&pair->remote->addr, tmpbuf2);
3420 nice_debug ("Agent %p : new pair %p : [%s]:%u --> [%s]:%u", agent, pair,
3421 tmpbuf1, nice_address_get_port (&pair->local->addr),
3422 tmpbuf2, nice_address_get_port (&pair->remote->addr));
3424 g_snprintf (pair->foundation, NICE_CANDIDATE_PAIR_MAX_FOUNDATION, "%s:%s",
3425 local_cand->foundation, parent_pair->remote->foundation);
3427 if (agent->controlling_mode == TRUE)
3428 pair->priority = nice_candidate_pair_priority (pair->local->priority,
3429 pair->remote->priority);
3431 pair->priority = nice_candidate_pair_priority (pair->remote->priority,
3432 pair->local->priority);
3433 pair->nominated = parent_pair->nominated;
3434 /* the peer-reflexive priority used in stun request is copied from
3435 * the parent succeeded pair. This value is not required for discovered
3436 * pair, that won't emit stun requests themselves, but may be used when
3437 * such pair becomes the selected pair, and when keepalive stun are emitted,
3438 * using the sockptr and stun_priority values from the succeeded pair.
3440 pair->stun_priority = parent_pair->stun_priority;
3441 nice_debug ("Agent %p : added a new peer-discovered pair %p with "
3442 "foundation '%s' and transport %s:%s to stream %u component %u",
3443 agent, pair, pair->foundation,
3444 priv_candidate_transport_to_string (pair->local->transport),
3445 priv_candidate_transport_to_string (pair->remote->transport),
3446 stream_id, component->id);
3448 stream->conncheck_list = g_slist_insert_sorted (stream->conncheck_list, pair,
3449 (GCompareFunc)conn_check_compare);
3455 * Recalculates priorities of all candidate pairs. This
3456 * is required after a conflict in ICE roles.
3458 void recalculate_pair_priorities (NiceAgent *agent)
3462 for (i = agent->streams; i; i = i->next) {
3463 NiceStream *stream = i->data;
3464 for (j = stream->conncheck_list; j; j = j->next) {
3465 CandidateCheckPair *p = j->data;
3466 p->priority = agent_candidate_pair_priority (agent, p->local, p->remote);
3468 stream->conncheck_list = g_slist_sort (stream->conncheck_list,
3469 (GCompareFunc)conn_check_compare);
3474 * Change the agent role if different from 'control'. Can be
3475 * initiated both by handling of incoming connectivity checks,
3476 * and by processing the responses to checks sent by us.
3478 static void priv_check_for_role_conflict (NiceAgent *agent, gboolean control)
3480 /* role conflict, change mode; wait for a new conn. check */
3481 if (control != agent->controlling_mode) {
3482 nice_debug ("Agent %p : Role conflict, changing agent role to \"%s\".",
3483 agent, control ? "controlling" : "controlled");
3484 agent->controlling_mode = control;
3485 /* the pair priorities depend on the roles, so recalculation
3487 recalculate_pair_priorities (agent);
3490 nice_debug ("Agent %p : Role conflict, staying with role \"%s\".",
3491 agent, control ? "controlling" : "controlled");
3495 * Checks whether the mapped address in connectivity check response
3496 * matches any of the known local candidates. If not, apply the
3497 * mechanism for "Discovering Peer Reflexive Candidates" ICE ID-19)
3499 * @param agent context pointer
3500 * @param stream which stream (of the agent)
3501 * @param component which component (of the stream)
3502 * @param p the connectivity check pair for which we got a response
3503 * @param socketptr socket used to send the reply
3504 * @param mapped_sockaddr mapped address in the response
3506 * @return pointer to a candidate pair, found in conncheck list or newly created
3508 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)
3510 CandidateCheckPair *new_pair = NULL;
3513 NiceCandidate *local_cand = NULL;
3515 nice_address_set_from_sockaddr (&mapped, mapped_sockaddr);
3517 for (i = component->local_candidates; i; i = i->next) {
3518 NiceCandidate *cand = i->data;
3520 if (nice_address_equal (&mapped, &cand->addr) &&
3521 local_candidate_and_socket_compatible (agent, cand, sockptr)) {
3527 /* The mapped address allows to look for a previously discovered
3528 * peer reflexive local candidate, and its related pair. This
3529 * new_pair will be marked 'Valid', while the pair 'p' of the
3530 * initial stun request will be marked 'Succeeded'
3532 * In the case of a tcp-act/tcp-pass pair 'p', where the local
3533 * candidate is of type tcp-act, and its port number is zero, a
3534 * conncheck on this pair *always* leads to the creation of a
3535 * discovered peer-reflexive tcp-act local candidate.
3537 for (i = stream->conncheck_list; i; i = i->next) {
3538 CandidateCheckPair *pair = i->data;
3539 if (local_cand == pair->local && remote_candidate == pair->remote) {
3546 /* note: when new_pair is distinct from p, it means new_pair is a
3547 * previously discovered peer-reflexive candidate pair, so we don't
3548 * set the valid flag on p in this case, because the valid flag is
3549 * already set on the discovered pair.
3553 SET_PAIR_STATE (agent, p, NICE_CHECK_SUCCEEDED);
3554 priv_remove_pair_from_triggered_check_queue (agent, p);
3555 priv_free_all_stun_transactions (p, component);
3556 nice_component_add_valid_candidate (agent, component, remote_candidate);
3559 if (local_cand == NULL && !agent->force_relay) {
3560 /* step: find a new local candidate, see RFC 5245 7.1.3.2.1.
3561 * "Discovering Peer Reflexive Candidates"
3563 * The priority equal to the value of the PRIORITY attribute
3564 * in the Binding request is taken from the "parent" pair p
3566 local_cand = discovery_add_peer_reflexive_candidate (agent,
3574 nice_debug ("Agent %p : added a new peer-reflexive local candidate %p "
3575 "with transport %s", agent, local_cand,
3576 priv_candidate_transport_to_string (local_cand->transport));
3579 /* step: add a new discovered pair (see RFC 5245 7.1.3.2.2
3580 "Constructing a Valid Pair") */
3582 new_pair = priv_add_peer_reflexive_pair (agent, stream->id, component,
3584 /* note: this is same as "adding to VALID LIST" in the spec
3587 new_pair->valid = TRUE;
3588 /* step: The agent sets the state of the pair that *generated* the check to
3589 * Succeeded, RFC 5245, 7.1.3.2.3, "Updating Pair States"
3591 SET_PAIR_STATE (agent, p, NICE_CHECK_SUCCEEDED);
3592 priv_remove_pair_from_triggered_check_queue (agent, p);
3593 priv_free_all_stun_transactions (p, component);
3596 if (new_pair && new_pair->valid)
3597 nice_component_add_valid_candidate (agent, component, remote_candidate);
3604 * Tries to match STUN reply in 'buf' to an existing STUN connectivity
3605 * check transaction. If found, the reply is processed. Implements
3606 * section 7.1.2 "Processing the Response" of ICE spec (ID-19).
3608 * @return TRUE if a matching transaction is found
3610 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)
3613 struct sockaddr_storage storage;
3614 struct sockaddr addr;
3616 socklen_t socklen = sizeof (sockaddr);
3619 StunUsageIceReturn res;
3620 StunTransactionId discovery_id;
3621 StunTransactionId response_id;
3622 stun_message_id (resp, response_id);
3624 for (i = stream->conncheck_list; i; i = i->next) {
3625 CandidateCheckPair *p = i->data;
3627 for (j = p->stun_transactions, k = 0; j; j = j->next, k++) {
3628 StunTransaction *stun = j->data;
3630 stun_message_id (&stun->message, discovery_id);
3632 if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)))
3635 res = stun_usage_ice_conncheck_process (resp,
3636 &sockaddr.storage, &socklen,
3637 agent_to_ice_compatibility (agent));
3638 nice_debug ("Agent %p : stun_bind_process/conncheck for %p: "
3639 "%s,res=%s,stun#=%d.",
3641 agent->controlling_mode ? "controlling" : "controlled",
3642 priv_ice_return_to_string (res), k);
3644 if (res == STUN_USAGE_ICE_RETURN_SUCCESS ||
3645 res == STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS) {
3646 /* case: found a matching connectivity check request */
3648 CandidateCheckPair *ok_pair = NULL;
3650 nice_debug ("Agent %p : pair %p MATCHED.", agent, p);
3651 priv_remove_stun_transaction (p, stun, component);
3653 /* step: verify that response came from the same IP address we
3654 * sent the original request to (see 7.1.2.1. "Failure
3656 if (nice_address_equal (from, &p->remote->addr) == FALSE) {
3657 candidate_check_pair_fail (stream, agent, p);
3658 if (nice_debug_is_enabled ()) {
3659 gchar tmpbuf[INET6_ADDRSTRLEN];
3660 gchar tmpbuf2[INET6_ADDRSTRLEN];
3661 nice_debug ("Agent %p : pair %p FAILED"
3662 " (mismatch of source address).", agent, p);
3663 nice_address_to_string (&p->remote->addr, tmpbuf);
3664 nice_address_to_string (from, tmpbuf2);
3665 nice_debug ("Agent %p : '%s:%u' != '%s:%u'", agent,
3666 tmpbuf, nice_address_get_port (&p->remote->addr),
3667 tmpbuf2, nice_address_get_port (from));
3672 if (remote_candidate == NULL) {
3673 candidate_check_pair_fail (stream, agent, p);
3674 if (nice_debug_is_enabled ()) {
3675 nice_debug ("Agent %p : pair %p FAILED "
3676 "(got a matching pair without a known remote candidate).", agent, p);
3681 /* note: CONNECTED but not yet READY, see docs */
3683 /* step: handle the possible case of a peer-reflexive
3684 * candidate where the mapped-address in response does
3685 * not match any local candidate, see 7.1.2.2.1
3686 * "Discovering Peer Reflexive Candidates" ICE ID-19) */
3688 if (res == STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS) {
3689 nice_debug ("Agent %p : Mapped address not found", agent);
3690 SET_PAIR_STATE (agent, p, NICE_CHECK_SUCCEEDED);
3692 nice_component_add_valid_candidate (agent, component, p->remote);
3694 ok_pair = priv_process_response_check_for_reflexive (agent,
3695 stream, component, p, sockptr, &sockaddr.addr,
3696 local_candidate, remote_candidate);
3698 /* note: The success of this check might also
3699 * cause the state of other checks to change as well, ICE
3702 priv_conn_check_unfreeze_related (agent, stream, p);
3704 /* Note: this assignment helps to reduce the numbers of cases
3705 * to be tested. If ok_pair and p refer to distinct pairs, it
3706 * means that ok_pair is a discovered peer reflexive one,
3707 * caused by the check made on pair p. In that case, the
3708 * flags to be tested are on p, but the nominated flag will be
3709 * set on ok_pair. When there's no discovered pair, p and
3710 * ok_pair refer to the same pair.
3711 * To summarize : p is a SUCCEEDED pair, ok_pair is a
3712 * DISCOVERED, VALID, and eventually NOMINATED pair.
3717 /* step: updating nominated flag (ICE 7.1.2.2.4 "Updating the
3718 Nominated Flag" (ID-19) */
3719 if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
3720 nice_debug ("Agent %p : Updating nominated flag (%s): "
3721 "ok_pair=%p (%d/%d) p=%p (%d/%d) (ucnc/mnora)",
3722 agent, p->local->transport == NICE_CANDIDATE_TRANSPORT_UDP ?
3724 ok_pair, ok_pair->use_candidate_on_next_check,
3725 ok_pair->mark_nominated_on_response_arrival,
3726 p, p->use_candidate_on_next_check,
3727 p->mark_nominated_on_response_arrival);
3729 if (agent->controlling_mode) {
3730 switch (agent->nomination_mode) {
3731 case NICE_NOMINATION_MODE_REGULAR:
3732 if (p->use_candidate_on_next_check) {
3733 nice_debug ("Agent %p : marking pair %p (%s) as nominated "
3734 "(regular nomination, controlling, "
3735 "use_cand_on_next_check=1).",
3736 agent, ok_pair, ok_pair->foundation);
3737 ok_pair->nominated = TRUE;
3740 case NICE_NOMINATION_MODE_AGGRESSIVE:
3741 if (!p->nominated) {
3742 nice_debug ("Agent %p : marking pair %p (%s) as nominated "
3743 "(aggressive nomination, controlling).",
3744 agent, ok_pair, ok_pair->foundation);
3745 ok_pair->nominated = TRUE;
3753 if (p->mark_nominated_on_response_arrival) {
3754 nice_debug ("Agent %p : marking pair %p (%s) as nominated "
3755 "(%s nomination, controlled, mark_on_response=1).",
3756 agent, ok_pair, ok_pair->foundation,
3757 agent->nomination_mode == NICE_NOMINATION_MODE_AGGRESSIVE ?
3758 "aggressive" : "regular");
3759 ok_pair->nominated = TRUE;
3764 if (ok_pair->nominated == TRUE) {
3765 conn_check_update_selected_pair (agent, component, ok_pair);
3766 priv_print_conn_check_lists (agent, G_STRFUNC,
3767 ", got a nominated pair");
3769 /* Do not step down to CONNECTED if we're already at state READY*/
3770 if (component->state != NICE_COMPONENT_STATE_READY)
3771 /* step: notify the client of a new component state (must be done
3772 * before the possible check list state update step */
3773 agent_signal_component_state_change (agent,
3774 stream->id, component->id, NICE_COMPONENT_STATE_CONNECTED);
3777 /* step: update pair states (ICE 7.1.2.2.3 "Updating pair
3778 states" and 8.1.2 "Updating States", ID-19) */
3779 conn_check_update_check_list_state_for_ready (agent, stream, component);
3780 } else if (res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT) {
3782 gboolean controlled_mode;
3784 if (!p->retransmit) {
3785 nice_debug ("Agent %p : Role conflict with pair %p, not restarting",
3790 /* case: role conflict error, need to restart with new role */
3791 nice_debug ("Agent %p : Role conflict with pair %p, restarting",
3794 /* note: this res value indicates that the role of the peer
3795 * agent has not changed after the tie-breaker comparison, so
3796 * this is our role that must change. see ICE sect. 7.1.3.1
3797 * "Failure Cases". Our role might already have changed due to
3798 * an earlier incoming request, but if not, change role now.
3800 * Sect. 7.1.3.1 is not clear on this point, but we choose to
3801 * put the candidate pair in the triggered check list even
3802 * when the agent did not switch its role. The reason for this
3803 * interpretation is that the reception of the stun reply, even
3804 * an error reply, is a good sign that this pair will be
3805 * valid, if we retry the check after the role of both peers
3808 controlled_mode = (stun_message_find64 (&stun->message,
3809 STUN_ATTRIBUTE_ICE_CONTROLLED, &tie) ==
3810 STUN_MESSAGE_RETURN_SUCCESS);
3812 priv_check_for_role_conflict (agent, controlled_mode);
3813 priv_remove_stun_transaction (p, stun, component);
3814 priv_add_pair_to_triggered_check_queue (agent, p);
3816 /* case: STUN error, the check STUN context was freed */
3817 candidate_check_pair_fail (stream, agent, p);
3827 * Tries to match STUN reply in 'buf' to an existing STUN discovery
3828 * transaction. If found, a reply is sent.
3830 * @return TRUE if a matching transaction is found
3832 static gboolean priv_map_reply_to_discovery_request (NiceAgent *agent, StunMessage *resp)
3835 struct sockaddr_storage storage;
3836 struct sockaddr addr;
3838 socklen_t socklen = sizeof (sockaddr);
3841 struct sockaddr_storage storage;
3842 struct sockaddr addr;
3844 socklen_t alternatelen = sizeof (sockaddr);
3847 StunUsageBindReturn res;
3848 gboolean trans_found = FALSE;
3849 StunTransactionId discovery_id;
3850 StunTransactionId response_id;
3851 stun_message_id (resp, response_id);
3853 for (i = agent->discovery_list; i && trans_found != TRUE; i = i->next) {
3854 CandidateDiscovery *d = i->data;
3856 if (d->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE &&
3857 d->stun_message.buffer) {
3858 stun_message_id (&d->stun_message, discovery_id);
3860 if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)) == 0) {
3861 res = stun_usage_bind_process (resp, &sockaddr.addr,
3862 &socklen, &alternate.addr, &alternatelen);
3863 nice_debug ("Agent %p : stun_bind_process/disc for %p res %d.",
3864 agent, d, (int)res);
3866 if (res == STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER) {
3867 /* handle alternate server */
3868 NiceAddress niceaddr;
3869 nice_address_set_from_sockaddr (&niceaddr, &alternate.addr);
3870 d->server = niceaddr;
3873 agent->discovery_unsched_items++;
3874 } else if (res == STUN_USAGE_BIND_RETURN_SUCCESS) {
3875 /* case: successful binding discovery, create a new local candidate */
3877 if (!agent->force_relay) {
3878 NiceAddress niceaddr;
3880 nice_address_set_from_sockaddr (&niceaddr, &sockaddr.addr);
3881 discovery_add_server_reflexive_candidate (
3886 NICE_CANDIDATE_TRANSPORT_UDP,
3889 if (agent->use_ice_tcp)
3890 discovery_discover_tcp_server_reflexive_candidates (
3897 d->stun_message.buffer = NULL;
3898 d->stun_message.buffer_len = 0;
3901 } else if (res == STUN_USAGE_BIND_RETURN_ERROR) {
3902 /* case: STUN error, the check STUN context was freed */
3903 d->stun_message.buffer = NULL;
3904 d->stun_message.buffer_len = 0;
3916 priv_calc_turn_timeout (guint lifetime)
3919 return lifetime - 60;
3921 return lifetime / 2;
3924 static CandidateRefresh *
3925 priv_add_new_turn_refresh (NiceAgent *agent, CandidateDiscovery *cdisco,
3926 NiceCandidate *relay_cand, guint lifetime)
3928 CandidateRefresh *cand;
3930 cand = g_slice_new0 (CandidateRefresh);
3931 agent->refresh_list = g_slist_append (agent->refresh_list, cand);
3933 cand->candidate = relay_cand;
3934 cand->nicesock = cdisco->nicesock;
3935 cand->server = cdisco->server;
3936 cand->stream_id = cdisco->stream_id;
3937 cand->component_id = cdisco->component_id;
3938 memcpy (&cand->stun_agent, &cdisco->stun_agent, sizeof(StunAgent));
3940 /* Use previous stun response for authentication credentials */
3941 if (cdisco->stun_resp_msg.buffer != NULL) {
3942 memcpy(cand->stun_resp_buffer, cdisco->stun_resp_buffer,
3943 sizeof(cand->stun_resp_buffer));
3944 memcpy(&cand->stun_resp_msg, &cdisco->stun_resp_msg, sizeof(StunMessage));
3945 cand->stun_resp_msg.buffer = cand->stun_resp_buffer;
3946 cand->stun_resp_msg.agent = NULL;
3947 cand->stun_resp_msg.key = NULL;
3950 nice_debug ("Agent %p : Adding new refresh candidate %p with timeout %d",
3951 agent, cand, priv_calc_turn_timeout (lifetime));
3952 /* step: also start the refresh timer */
3953 /* refresh should be sent 1 minute before it expires */
3954 agent_timeout_add_seconds_with_context (agent, &cand->timer_source,
3955 "Candidate TURN refresh",
3956 priv_calc_turn_timeout (lifetime),
3957 priv_turn_allocate_refresh_tick_agent_locked, cand);
3959 nice_debug ("timer source is : %p", cand->timer_source);
3964 static void priv_handle_turn_alternate_server (NiceAgent *agent,
3965 CandidateDiscovery *disco, NiceAddress server, NiceAddress alternate)
3967 /* We need to cancel and reset all candidate discovery turn for the same
3968 stream and type if there is an alternate server. Otherwise, we might end up
3969 with two relay components on different servers, creating candidates with
3970 unique foundations that only contain one component.
3974 for (i = agent->discovery_list; i; i = i->next) {
3975 CandidateDiscovery *d = i->data;
3978 d->type == disco->type &&
3979 d->stream_id == disco->stream_id &&
3980 d->turn->type == disco->turn->type &&
3981 nice_address_equal (&d->server, &server)) {
3982 gchar ip[INET6_ADDRSTRLEN];
3983 // Cancel the pending request to avoid a race condition with another
3984 // component responding with another altenrate-server
3985 d->stun_message.buffer = NULL;
3986 d->stun_message.buffer_len = 0;
3988 nice_address_to_string (&server, ip);
3989 nice_debug ("Agent %p : Cancelling and setting alternate server %s for "
3990 "CandidateDiscovery %p", agent, ip, d);
3991 d->server = alternate;
3992 d->turn->server = alternate;
3994 agent->discovery_unsched_items++;
4000 * Tries to match STUN reply in 'buf' to an existing STUN discovery
4001 * transaction. If found, a reply is sent.
4003 * @return TRUE if a matching transaction is found
4005 static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *resp)
4008 struct sockaddr_storage storage;
4009 struct sockaddr addr;
4011 socklen_t socklen = sizeof (sockaddr);
4014 struct sockaddr_storage storage;
4015 struct sockaddr addr;
4017 socklen_t alternatelen = sizeof (alternate);
4020 struct sockaddr_storage storage;
4021 struct sockaddr addr;
4023 socklen_t relayaddrlen = sizeof (relayaddr);
4028 StunUsageTurnReturn res;
4029 gboolean trans_found = FALSE;
4030 StunTransactionId discovery_id;
4031 StunTransactionId response_id;
4032 stun_message_id (resp, response_id);
4034 for (i = agent->discovery_list; i && trans_found != TRUE; i = i->next) {
4035 CandidateDiscovery *d = i->data;
4037 if (d->type == NICE_CANDIDATE_TYPE_RELAYED &&
4038 d->stun_message.buffer) {
4039 stun_message_id (&d->stun_message, discovery_id);
4041 if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)) == 0) {
4042 res = stun_usage_turn_process (resp,
4043 &relayaddr.storage, &relayaddrlen,
4044 &sockaddr.storage, &socklen,
4045 &alternate.storage, &alternatelen,
4046 &bandwidth, &lifetime, agent_to_turn_compatibility (agent));
4047 nice_debug ("Agent %p : stun_turn_process/disc for %p res %d.",
4048 agent, d, (int)res);
4050 if (res == STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER) {
4053 /* handle alternate server */
4054 nice_address_set_from_sockaddr (&addr, &alternate.addr);
4055 priv_handle_turn_alternate_server (agent, d, d->server, addr);
4057 } else if (res == STUN_USAGE_TURN_RETURN_RELAY_SUCCESS ||
4058 res == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS) {
4059 /* case: successful allocate, create a new local candidate */
4060 NiceAddress niceaddr;
4061 NiceCandidate *relay_cand;
4063 nice_address_set_from_sockaddr (&niceaddr, &relayaddr.addr);
4065 if (res == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS) {
4066 NiceAddress mappedniceaddr;
4068 /* We also received our mapped address */
4069 nice_address_set_from_sockaddr (&mappedniceaddr, &sockaddr.addr);
4071 /* TCP or TLS TURNS means the server-reflexive address was
4072 * on a TCP connection, which cannot be used for server-reflexive
4073 * discovery of candidates.
4075 if (d->turn->type == NICE_RELAY_TYPE_TURN_UDP &&
4076 !agent->force_relay) {
4077 discovery_add_server_reflexive_candidate (
4082 NICE_CANDIDATE_TRANSPORT_UDP,
4086 if (agent->use_ice_tcp) {
4087 if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4088 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
4089 !nice_address_equal_no_port (&niceaddr, &d->turn->server)) {
4090 nice_debug("TURN port got allocated on an alternate server, "
4091 "ignoring bogus srflx address");
4093 discovery_discover_tcp_server_reflexive_candidates (
4103 if (nice_socket_is_reliable (d->nicesock)) {
4104 relay_cand = discovery_add_relay_candidate (
4109 NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE,
4114 if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4115 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
4116 nice_udp_turn_socket_set_ms_realm(relay_cand->sockptr,
4118 nice_udp_turn_socket_set_ms_connection_id(relay_cand->sockptr,
4121 priv_add_new_turn_refresh (agent, d, relay_cand, lifetime);
4125 relay_cand = discovery_add_relay_candidate (
4130 NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE,
4134 relay_cand = discovery_add_relay_candidate (
4139 NICE_CANDIDATE_TRANSPORT_UDP,
4145 if (d->stun_resp_msg.buffer)
4146 nice_udp_turn_socket_cache_realm_nonce (relay_cand->sockptr,
4148 if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4149 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
4150 /* These data are needed on TURN socket when sending requests,
4151 * but never reach nice_turn_socket_parse_recv() where it could
4152 * be read directly, as the socket does not exist when allocate
4153 * response arrives to _nice_agent_recv(). We must set them right
4154 * after socket gets created in discovery_add_relay_candidate(),
4155 * so we are doing it here. */
4156 nice_udp_turn_socket_set_ms_realm(relay_cand->sockptr,
4158 nice_udp_turn_socket_set_ms_connection_id(relay_cand->sockptr,
4161 priv_add_new_turn_refresh (agent, d, relay_cand, lifetime);
4164 /* In case a new candidate has been added */
4165 conn_check_schedule_next (agent);
4168 d->stun_message.buffer = NULL;
4169 d->stun_message.buffer_len = 0;
4172 } else if (res == STUN_USAGE_TURN_RETURN_ERROR) {
4174 uint8_t *sent_realm = NULL;
4175 uint8_t *recv_realm = NULL;
4176 uint16_t sent_realm_len = 0;
4177 uint16_t recv_realm_len = 0;
4179 sent_realm = (uint8_t *) stun_message_find (&d->stun_message,
4180 STUN_ATTRIBUTE_REALM, &sent_realm_len);
4181 recv_realm = (uint8_t *) stun_message_find (resp,
4182 STUN_ATTRIBUTE_REALM, &recv_realm_len);
4184 if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4185 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
4186 alternatelen != sizeof(alternate)) {
4189 nice_address_set_from_sockaddr (&addr, &alternate.addr);
4191 if (!nice_address_equal (&addr, &d->server)) {
4192 priv_handle_turn_alternate_server (agent, d, d->server, addr);
4195 /* check for unauthorized error response */
4196 if ((agent->compatibility == NICE_COMPATIBILITY_RFC5245 ||
4197 agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4198 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
4199 stun_message_get_class (resp) == STUN_ERROR &&
4200 stun_message_find_error (resp, &code) ==
4201 STUN_MESSAGE_RETURN_SUCCESS &&
4202 recv_realm != NULL && recv_realm_len > 0) {
4204 if (code == STUN_ERROR_STALE_NONCE ||
4205 (code == STUN_ERROR_UNAUTHORIZED &&
4206 !(recv_realm_len == sent_realm_len &&
4207 sent_realm != NULL &&
4208 memcmp (sent_realm, recv_realm, sent_realm_len) == 0))) {
4209 d->stun_resp_msg = *resp;
4210 memcpy (d->stun_resp_buffer, resp->buffer,
4211 stun_message_length (resp));
4212 d->stun_resp_msg.buffer = d->stun_resp_buffer;
4213 d->stun_resp_msg.buffer_len = sizeof(d->stun_resp_buffer);
4215 agent->discovery_unsched_items++;
4217 /* case: a real unauthorized error */
4218 d->stun_message.buffer = NULL;
4219 d->stun_message.buffer_len = 0;
4223 /* case: STUN error, the check STUN context was freed */
4224 d->stun_message.buffer = NULL;
4225 d->stun_message.buffer_len = 0;
4239 * Tries to match STUN reply in 'buf' to an existing STUN discovery
4240 * transaction. If found, a reply is sent.
4242 * @return TRUE if a matching transaction is found
4244 static gboolean priv_map_reply_to_relay_refresh (NiceAgent *agent, StunMessage *resp)
4248 StunUsageTurnReturn res;
4249 gboolean trans_found = FALSE;
4250 StunTransactionId refresh_id;
4251 StunTransactionId response_id;
4252 stun_message_id (resp, response_id);
4254 for (i = agent->refresh_list; i && trans_found != TRUE;) {
4255 CandidateRefresh *cand = i->data;
4256 GSList *next = i->next;
4258 if (!cand->disposing && cand->stun_message.buffer) {
4259 stun_message_id (&cand->stun_message, refresh_id);
4261 if (memcmp (refresh_id, response_id, sizeof(StunTransactionId)) == 0) {
4262 res = stun_usage_turn_refresh_process (resp,
4263 &lifetime, agent_to_turn_compatibility (agent));
4264 nice_debug ("Agent %p : stun_turn_refresh_process for %p res %d with lifetime %u.",
4265 agent, cand, (int)res, lifetime);
4266 if (res == STUN_USAGE_TURN_RETURN_RELAY_SUCCESS) {
4267 /* refresh should be sent 1 minute before it expires */
4268 agent_timeout_add_seconds_with_context (agent,
4269 &cand->timer_source,
4270 "Candidate TURN refresh", priv_calc_turn_timeout (lifetime),
4271 priv_turn_allocate_refresh_tick_agent_locked, cand);
4273 g_source_destroy (cand->tick_source);
4274 g_source_unref (cand->tick_source);
4275 cand->tick_source = NULL;
4277 } else if (res == STUN_USAGE_TURN_RETURN_ERROR) {
4279 uint8_t *sent_realm = NULL;
4280 uint8_t *recv_realm = NULL;
4281 uint16_t sent_realm_len = 0;
4282 uint16_t recv_realm_len = 0;
4284 sent_realm = (uint8_t *) stun_message_find (&cand->stun_message,
4285 STUN_ATTRIBUTE_REALM, &sent_realm_len);
4286 recv_realm = (uint8_t *) stun_message_find (resp,
4287 STUN_ATTRIBUTE_REALM, &recv_realm_len);
4289 /* check for unauthorized error response */
4290 if (agent->compatibility == NICE_COMPATIBILITY_RFC5245 &&
4291 stun_message_get_class (resp) == STUN_ERROR &&
4292 stun_message_find_error (resp, &code) ==
4293 STUN_MESSAGE_RETURN_SUCCESS &&
4294 recv_realm != NULL && recv_realm_len > 0) {
4296 if (code == STUN_ERROR_STALE_NONCE ||
4297 (code == STUN_ERROR_UNAUTHORIZED &&
4298 !(recv_realm_len == sent_realm_len &&
4299 sent_realm != NULL &&
4300 memcmp (sent_realm, recv_realm, sent_realm_len) == 0))) {
4301 cand->stun_resp_msg = *resp;
4302 memcpy (cand->stun_resp_buffer, resp->buffer,
4303 stun_message_length (resp));
4304 cand->stun_resp_msg.buffer = cand->stun_resp_buffer;
4305 cand->stun_resp_msg.buffer_len = sizeof(cand->stun_resp_buffer);
4306 priv_turn_allocate_refresh_tick_unlocked (agent, cand);
4308 /* case: a real unauthorized error */
4309 refresh_free (agent, cand);
4312 /* case: STUN error, the check STUN context was freed */
4313 refresh_free (agent, cand);
4325 static gboolean priv_map_reply_to_relay_remove (NiceAgent *agent,
4328 StunTransactionId response_id;
4331 stun_message_id (resp, response_id);
4333 for (i = agent->refresh_list; i; i = i->next) {
4334 CandidateRefresh *cand = i->data;
4335 StunTransactionId request_id;
4336 StunUsageTurnReturn res;
4339 if (!cand->disposing || !cand->stun_message.buffer) {
4343 stun_message_id (&cand->stun_message, request_id);
4345 if (memcmp (request_id, response_id, sizeof(StunTransactionId)) == 0) {
4346 res = stun_usage_turn_refresh_process (resp, &lifetime,
4347 agent_to_turn_compatibility (agent));
4349 nice_debug ("Agent %p : priv_map_reply_to_relay_remove for %p res %d "
4350 "with lifetime %u.", agent, cand, res, lifetime);
4352 if (res != STUN_USAGE_TURN_RETURN_INVALID) {
4353 refresh_free (agent, cand);
4362 static gboolean priv_map_reply_to_keepalive_conncheck (NiceAgent *agent,
4363 NiceComponent *component, StunMessage *resp)
4365 StunTransactionId conncheck_id;
4366 StunTransactionId response_id;
4367 stun_message_id (resp, response_id);
4369 if (component->selected_pair.keepalive.stun_message.buffer) {
4370 stun_message_id (&component->selected_pair.keepalive.stun_message,
4372 if (memcmp (conncheck_id, response_id, sizeof(StunTransactionId)) == 0) {
4373 nice_debug ("Agent %p : Keepalive for selected pair received.",
4375 if (component->selected_pair.keepalive.tick_source) {
4376 g_source_destroy (component->selected_pair.keepalive.tick_source);
4377 g_source_unref (component->selected_pair.keepalive.tick_source);
4378 component->selected_pair.keepalive.tick_source = NULL;
4380 component->selected_pair.keepalive.stun_message.buffer = NULL;
4392 NiceComponent *component;
4394 } conncheck_validater_data;
4396 static bool conncheck_stun_validater (StunAgent *agent,
4397 StunMessage *message, uint8_t *username, uint16_t username_len,
4398 uint8_t **password, size_t *password_len, void *user_data)
4400 conncheck_validater_data *data = (conncheck_validater_data*) user_data;
4402 gchar *ufrag = NULL;
4405 gboolean msn_msoc_nice_compatibility =
4406 data->agent->compatibility == NICE_COMPATIBILITY_MSN ||
4407 data->agent->compatibility == NICE_COMPATIBILITY_OC2007;
4409 if (data->agent->compatibility == NICE_COMPATIBILITY_OC2007 &&
4410 stun_message_get_class (message) == STUN_RESPONSE)
4411 i = data->component->remote_candidates;
4413 i = data->component->local_candidates;
4415 for (; i; i = i->next) {
4416 NiceCandidate *cand = i->data;
4420 ufrag = cand->username;
4422 ufrag = data->stream->local_ufrag;
4423 ufrag_len = ufrag? strlen (ufrag) : 0;
4425 if (ufrag && msn_msoc_nice_compatibility)
4426 ufrag = (gchar *)g_base64_decode (ufrag, &ufrag_len);
4431 stun_debug ("Comparing username/ufrag of len %d and %" G_GSIZE_FORMAT ", equal=%d",
4432 username_len, ufrag_len, username_len >= ufrag_len ?
4433 memcmp (username, ufrag, ufrag_len) : 0);
4434 stun_debug_bytes (" username: ", username, username_len);
4435 stun_debug_bytes (" ufrag: ", ufrag, ufrag_len);
4436 if (ufrag_len > 0 && username_len >= ufrag_len &&
4437 memcmp (username, ufrag, ufrag_len) == 0) {
4441 pass = cand->password;
4442 else if (data->stream && data->stream->local_password[0])
4443 pass = data->stream->local_password;
4446 *password = (uint8_t *) pass;
4447 *password_len = strlen (pass);
4449 if (msn_msoc_nice_compatibility) {
4452 data->password = g_base64_decode (pass, &pass_len);
4453 *password = data->password;
4454 *password_len = pass_len;
4458 if (msn_msoc_nice_compatibility)
4461 stun_debug ("Found valid username, returning password: '%s'", *password);
4465 if (msn_msoc_nice_compatibility)
4473 * handle RENOMINATION stun attribute
4474 * @return TRUE if nomination changed. FALSE otherwise
4476 static gboolean conn_check_handle_renomination (NiceAgent *agent, NiceStream *stream,
4477 NiceComponent *component, StunMessage *req,
4478 NiceCandidate *remote_candidate, NiceCandidate *local_candidate)
4481 if (!agent->controlling_mode && NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) &&
4482 agent->support_renomination && remote_candidate && local_candidate)
4484 uint32_t nom_value = 0;
4485 uint16_t nom_len = 0;
4486 const void *value = stun_message_find (req, STUN_ATTRIBUTE_NOMINATION, &nom_len);
4491 memcpy (&nom_value, value, 4);
4492 nom_value = ntohl (nom_value);
4494 nice_debug ("Agent %p : received NOMINATION attr with incorrect octet length %u, expected 4 bytes",
4499 if (nice_debug_is_enabled ()) {
4500 gchar remote_str[INET6_ADDRSTRLEN];
4501 nice_address_to_string(&remote_candidate->addr, remote_str);
4502 nice_debug ("Agent %p : received NOMINATION attr for remote candidate [%s]:%u, value is %u",
4503 agent, remote_str, nice_address_get_port (&remote_candidate->addr), nom_value);
4507 * If another pair is SELECTED, change this pair's priority to be greater than
4508 * selected pair's priority so this pair gets SELECTED!
4510 if (component->selected_pair.priority &&
4511 component->selected_pair.remote && component->selected_pair.remote != remote_candidate &&
4512 component->selected_pair.local && component->selected_pair.local != local_candidate) {
4513 for (lst = stream->conncheck_list; lst; lst = lst->next) {
4514 CandidateCheckPair *pair = lst->data;
4515 if (pair->local == local_candidate && pair->remote == remote_candidate) {
4517 pair->priority = component->selected_pair.priority + 1;
4523 priv_mark_pair_nominated (agent, stream, component, local_candidate, remote_candidate);
4530 * Processing an incoming STUN message.
4532 * @param agent self pointer
4533 * @param stream stream the packet is related to
4534 * @param component component the packet is related to
4535 * @param nicesock socket from which the packet was received
4536 * @param from address of the sender
4537 * @param buf message contents
4538 * @param buf message length
4540 * @pre contents of 'buf' is a STUN message
4542 * @return XXX (what FALSE means exactly?)
4544 gboolean conn_check_handle_inbound_stun (NiceAgent *agent, NiceStream *stream,
4545 NiceComponent *component, NiceSocket *nicesock, const NiceAddress *from,
4546 gchar *buf, guint len)
4549 struct sockaddr_storage storage;
4550 struct sockaddr addr;
4552 uint8_t rbuf[MAX_STUN_DATAGRAM_PAYLOAD];
4554 size_t rbuf_len = sizeof (rbuf);
4555 bool control = agent->controlling_mode;
4556 uint8_t uname[NICE_STREAM_MAX_UNAME];
4559 uint16_t username_len;
4562 StunValidationStatus valid;
4563 conncheck_validater_data validater_data = {agent, stream, component, NULL};
4565 NiceCandidate *remote_candidate = NULL;
4566 NiceCandidate *remote_candidate2 = NULL;
4567 NiceCandidate *local_candidate = NULL;
4568 gboolean discovery_msg = FALSE;
4570 nice_address_copy_to_sockaddr (from, &sockaddr.addr);
4572 /* note: contents of 'buf' already validated, so it is
4573 * a valid and fully received STUN message */
4575 if (nice_debug_is_enabled ()) {
4576 gchar tmpbuf[INET6_ADDRSTRLEN];
4577 nice_address_to_string (from, tmpbuf);
4578 nice_debug ("Agent %p: inbound STUN packet for %u/%u (stream/component) from [%s]:%u (%u octets) :",
4579 agent, stream->id, component->id, tmpbuf, nice_address_get_port (from), len);
4582 /* note: ICE 7.2. "STUN Server Procedures" (ID-19) */
4584 valid = stun_agent_validate (&component->stun_agent, &req,
4585 (uint8_t *) buf, len, conncheck_stun_validater, &validater_data);
4587 /* Check for discovery candidates stun agents */
4588 if (valid == STUN_VALIDATION_BAD_REQUEST ||
4589 valid == STUN_VALIDATION_UNMATCHED_RESPONSE) {
4590 for (i = agent->discovery_list; i; i = i->next) {
4591 CandidateDiscovery *d = i->data;
4592 if (d->stream_id == stream->id && d->component_id == component->id &&
4593 d->nicesock == nicesock) {
4594 valid = stun_agent_validate (&d->stun_agent, &req,
4595 (uint8_t *) buf, len, conncheck_stun_validater, &validater_data);
4597 if (valid == STUN_VALIDATION_UNMATCHED_RESPONSE)
4600 discovery_msg = TRUE;
4605 /* Check for relay refresh stun agents */
4606 if (valid == STUN_VALIDATION_BAD_REQUEST ||
4607 valid == STUN_VALIDATION_UNMATCHED_RESPONSE) {
4608 for (i = agent->refresh_list; i; i = i->next) {
4609 CandidateRefresh *r = i->data;
4611 nice_debug_verbose ("Comparing r.sid=%u to sid=%u, r.cid=%u to cid=%u and %p and %p to %p",
4612 r->stream_id, stream->id, r->component_id, component->id, r->nicesock,
4613 r->candidate->sockptr, nicesock);
4615 if (r->stream_id == stream->id && r->component_id == component->id &&
4616 (r->nicesock == nicesock || r->candidate->sockptr == nicesock)) {
4617 valid = stun_agent_validate (&r->stun_agent, &req,
4618 (uint8_t *) buf, len, conncheck_stun_validater, &validater_data);
4619 nice_debug ("Validating gave %d", valid);
4620 if (valid == STUN_VALIDATION_UNMATCHED_RESPONSE)
4622 discovery_msg = TRUE;
4628 g_free (validater_data.password);
4630 if (valid == STUN_VALIDATION_NOT_STUN ||
4631 valid == STUN_VALIDATION_INCOMPLETE_STUN ||
4632 valid == STUN_VALIDATION_BAD_REQUEST)
4634 nice_debug ("Agent %p : Incorrectly multiplexed STUN message ignored.",
4639 if (valid == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE) {
4640 nice_debug ("Agent %p : Unknown mandatory attributes in message.", agent);
4642 if (agent->compatibility != NICE_COMPATIBILITY_MSN &&
4643 agent->compatibility != NICE_COMPATIBILITY_OC2007) {
4644 rbuf_len = stun_agent_build_unknown_attributes_error (&component->stun_agent,
4645 &msg, rbuf, rbuf_len, &req);
4647 agent_socket_send (nicesock, from, rbuf_len, (const gchar*)rbuf);
4652 if (valid == STUN_VALIDATION_UNAUTHORIZED) {
4653 nice_debug ("Agent %p : Integrity check failed.", agent);
4655 if (stun_agent_init_error (&component->stun_agent, &msg, rbuf, rbuf_len,
4656 &req, STUN_ERROR_UNAUTHORIZED)) {
4657 rbuf_len = stun_agent_finish_message (&component->stun_agent, &msg, NULL, 0);
4658 if (rbuf_len > 0 && agent->compatibility != NICE_COMPATIBILITY_MSN &&
4659 agent->compatibility != NICE_COMPATIBILITY_OC2007)
4660 agent_socket_send (nicesock, from, rbuf_len, (const gchar*)rbuf);
4664 if (valid == STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST) {
4665 nice_debug ("Agent %p : Integrity check failed - bad request.", agent);
4666 if (stun_agent_init_error (&component->stun_agent, &msg, rbuf, rbuf_len,
4667 &req, STUN_ERROR_BAD_REQUEST)) {
4668 rbuf_len = stun_agent_finish_message (&component->stun_agent, &msg, NULL, 0);
4669 if (rbuf_len > 0 && agent->compatibility != NICE_COMPATIBILITY_MSN &&
4670 agent->compatibility != NICE_COMPATIBILITY_OC2007)
4671 agent_socket_send (nicesock, from, rbuf_len, (const gchar*)rbuf);
4676 username = (uint8_t *) stun_message_find (&req, STUN_ATTRIBUTE_USERNAME,
4679 for (i = component->local_candidates; i; i = i->next) {
4680 NiceCandidate *cand = i->data;
4683 if (cand->type == NICE_CANDIDATE_TYPE_RELAYED)
4686 addr = &cand->base_addr;
4688 if (nice_address_equal (&nicesock->addr, addr) &&
4689 local_candidate_and_socket_compatible (agent, cand, nicesock)) {
4690 local_candidate = cand;
4695 for (i = component->remote_candidates; i; i = i->next) {
4696 NiceCandidate *cand = i->data;
4697 if (nice_address_equal (from, &cand->addr) &&
4698 remote_candidate_and_socket_compatible (agent, local_candidate,
4700 remote_candidate = cand;
4705 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE ||
4706 agent->compatibility == NICE_COMPATIBILITY_MSN ||
4707 agent->compatibility == NICE_COMPATIBILITY_OC2007) {
4708 /* We need to find which local candidate was used */
4709 for (i = component->remote_candidates;
4710 i != NULL && remote_candidate2 == NULL; i = i->next) {
4711 for (j = component->local_candidates; j; j = j->next) {
4712 gboolean inbound = TRUE;
4713 NiceCandidate *rcand = i->data;
4714 NiceCandidate *lcand = j->data;
4716 /* If we receive a response, then the username is local:remote */
4717 if (agent->compatibility != NICE_COMPATIBILITY_MSN) {
4718 if (stun_message_get_class (&req) == STUN_REQUEST ||
4719 stun_message_get_class (&req) == STUN_INDICATION) {
4726 uname_len = priv_create_username (agent, stream,
4727 component->id, rcand, lcand,
4728 uname, sizeof (uname), inbound);
4732 stun_debug ("Comparing usernames of size %d and %d: %d",
4733 username_len, uname_len, username && uname_len == username_len &&
4734 memcmp (username, uname, uname_len) == 0);
4735 stun_debug_bytes (" First username: ", username,
4736 username ? username_len : 0);
4737 stun_debug_bytes (" Second uname: ", uname, uname_len);
4740 uname_len == username_len &&
4741 memcmp (uname, username, username_len) == 0) {
4742 local_candidate = lcand;
4743 remote_candidate2 = rcand;
4750 if (component->remote_candidates &&
4751 agent->compatibility == NICE_COMPATIBILITY_GOOGLE &&
4752 local_candidate == NULL &&
4753 discovery_msg == FALSE) {
4754 /* if we couldn't match the username and the stun agent has
4755 IGNORE_CREDENTIALS then we have an integrity check failing.
4756 This could happen with the race condition of receiving connchecks
4757 before the remote candidates are added. Just drop the message, and let
4758 the retransmissions make it work. */
4759 nice_debug ("Agent %p : Username check failed.", agent);
4763 /* This is most likely caused by a second response to a request which
4764 * already has received a valid reply.
4766 if (valid == STUN_VALIDATION_UNMATCHED_RESPONSE) {
4767 nice_debug ("Agent %p : Valid STUN response for which we don't have a request, ignoring", agent);
4771 if (valid != STUN_VALIDATION_SUCCESS) {
4772 nice_debug ("Agent %p : STUN message is unsuccessful %d, ignoring", agent, valid);
4777 if (stun_message_get_class (&req) == STUN_REQUEST) {
4778 if ( agent->compatibility == NICE_COMPATIBILITY_MSN
4779 || agent->compatibility == NICE_COMPATIBILITY_OC2007) {
4780 if (local_candidate && remote_candidate2) {
4783 if (agent->compatibility == NICE_COMPATIBILITY_MSN) {
4784 username = (uint8_t *) stun_message_find (&req,
4785 STUN_ATTRIBUTE_USERNAME, &username_len);
4786 uname_len = priv_create_username (agent, stream,
4787 component->id, remote_candidate2, local_candidate,
4788 uname, sizeof (uname), FALSE);
4789 memcpy (username, uname, MIN (uname_len, username_len));
4791 req.key = g_base64_decode ((gchar *) remote_candidate2->password,
4793 req.key_len = key_len;
4794 } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007) {
4795 req.key = g_base64_decode ((gchar *) local_candidate->password,
4797 req.key_len = key_len;
4800 nice_debug ("Agent %p : received MSN incoming check from unknown remote candidate. "
4801 "Ignoring request", agent);
4806 rbuf_len = sizeof (rbuf);
4807 res = stun_usage_ice_conncheck_create_reply (&component->stun_agent, &req,
4808 &msg, rbuf, &rbuf_len, &sockaddr.storage, sizeof (sockaddr),
4809 &control, agent->tie_breaker,
4810 agent_to_ice_compatibility (agent));
4812 if ( agent->compatibility == NICE_COMPATIBILITY_MSN
4813 || agent->compatibility == NICE_COMPATIBILITY_OC2007) {
4817 if (res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT)
4818 priv_check_for_role_conflict (agent, control);
4820 if (res == STUN_USAGE_ICE_RETURN_SUCCESS ||
4821 res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT) {
4822 /* case 1: valid incoming request, send a reply/error */
4823 bool use_candidate =
4824 stun_usage_ice_conncheck_use_candidate (&req);
4825 uint32_t priority = stun_usage_ice_conncheck_priority (&req);
4827 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE ||
4828 agent->compatibility == NICE_COMPATIBILITY_MSN ||
4829 agent->compatibility == NICE_COMPATIBILITY_OC2007)
4830 use_candidate = TRUE;
4832 if (stream->initial_binding_request_received != TRUE)
4833 agent_signal_initial_binding_request_received (agent, stream);
4835 if (remote_candidate == NULL) {
4836 nice_debug ("Agent %p : No matching remote candidate for incoming "
4837 "check -> peer-reflexive candidate.", agent);
4838 remote_candidate = discovery_learn_remote_peer_reflexive_candidate (
4839 agent, stream, component, priority, from, nicesock,
4841 remote_candidate2 ? remote_candidate2 : remote_candidate);
4842 if(remote_candidate && stream->remote_ufrag[0]) {
4843 if (local_candidate &&
4844 local_candidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) {
4845 CandidateCheckPair *pair;
4847 pair = priv_conn_check_add_for_candidate_pair_matched (agent,
4848 stream->id, component, local_candidate, remote_candidate,
4849 NICE_CHECK_SUCCEEDED);
4854 conn_check_add_for_candidate (agent, stream->id, component, remote_candidate);
4858 nice_component_add_valid_candidate (agent, component, remote_candidate);
4860 priv_reply_to_conn_check (agent, stream, component, local_candidate,
4861 remote_candidate, from, nicesock, rbuf_len, &msg, use_candidate);
4863 if (stream->remote_ufrag[0] == 0) {
4864 /* case: We've got a valid binding request to a local candidate
4865 * but we do not yet know remote credentials.
4866 * As per sect 7.2 of ICE (ID-19), we send a reply
4867 * immediately but postpone all other processing until
4868 * we get information about the remote candidates */
4870 /* step: send a reply immediately but postpone other processing */
4871 priv_store_pending_check (agent, component, from, nicesock,
4872 username, username_len, priority, use_candidate);
4873 priv_print_conn_check_lists (agent, G_STRFUNC, ", icheck stored");
4876 nice_debug ("Agent %p : Invalid STUN packet, ignoring... %s",
4877 agent, strerror(errno));
4881 /* case 2: not a new request, might be a reply... */
4882 gboolean trans_found = FALSE;
4884 /* note: ICE sect 7.1.2. "Processing the Response" (ID-19) */
4886 /* step: let's try to match the response to an existing check context */
4887 if (trans_found != TRUE)
4888 trans_found = priv_map_reply_to_conn_check_request (agent, stream,
4889 component, nicesock, from, local_candidate, remote_candidate, &req);
4891 /* step: let's try to match the response to an existing discovery */
4892 if (trans_found != TRUE)
4893 trans_found = priv_map_reply_to_discovery_request (agent, &req);
4895 /* step: let's try to match the response to an existing turn allocate */
4896 if (trans_found != TRUE)
4897 trans_found = priv_map_reply_to_relay_request (agent, &req);
4899 /* step: let's try to match the response to an existing turn refresh */
4900 if (trans_found != TRUE)
4901 trans_found = priv_map_reply_to_relay_refresh (agent, &req);
4903 if (trans_found != TRUE)
4904 trans_found = priv_map_reply_to_relay_remove (agent, &req);
4906 /* step: let's try to match the response to an existing keepalive conncheck */
4907 if (trans_found != TRUE)
4908 trans_found = priv_map_reply_to_keepalive_conncheck (agent, component,
4911 if (trans_found != TRUE)
4912 nice_debug ("Agent %p : Unable to match to an existing transaction, "
4913 "probably a keepalive.", agent);
4916 /* RENOMINATION attribute support */
4917 conn_check_handle_renomination(agent, stream, component, &req, remote_candidate, local_candidate);
4922 /* Remove all pointers to the given @sock from the connection checking process.
4923 * These are entirely NiceCandidates pointed to from various places. */
4925 conn_check_prune_socket (NiceAgent *agent, NiceStream *stream, NiceComponent *component,
4930 if (component->selected_pair.local &&
4931 component->selected_pair.local->sockptr == sock &&
4932 component->state == NICE_COMPONENT_STATE_READY) {
4933 nice_debug ("Agent %p: Selected pair socket %p has been destroyed, "
4934 "declaring failed", agent, sock);
4935 agent_signal_component_state_change (agent,
4936 stream->id, component->id, NICE_COMPONENT_STATE_FAILED);
4939 /* Prune from the candidate check pairs. */
4940 for (l = stream->conncheck_list; l != NULL;) {
4941 CandidateCheckPair *p = l->data;
4942 GSList *next = l->next;
4944 if ((p->local != NULL && p->local->sockptr == sock) ||
4945 (p->remote != NULL && p->remote->sockptr == sock) ||
4946 (p->sockptr == sock)) {
4947 nice_debug ("Agent %p : Retransmissions failed, giving up on pair %p",
4949 candidate_check_pair_fail (stream, agent, p);
4950 candidate_check_pair_free (agent, p);
4951 stream->conncheck_list = g_slist_delete_link (stream->conncheck_list, l);