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.
25 * Dafydd Harries, Collabora Ltd.
26 * Youness Alaoui, 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 component functions
53 #include "component.h"
54 #include "agent-priv.h"
57 component_new (guint id
)
61 component
= g_slice_new0 (Component
);
63 component
->state
= NICE_COMPONENT_STATE_DISCONNECTED
;
64 component
->restart_candidate
= NULL
;
65 component
->tcp
= NULL
;
72 component_free (Component
*cmp
)
77 for (i
= cmp
->local_candidates
; i
; i
= i
->next
) {
78 NiceCandidate
*candidate
= i
->data
;
79 nice_candidate_free (candidate
);
82 for (i
= cmp
->remote_candidates
; i
; i
= i
->next
) {
83 NiceCandidate
*candidate
= i
->data
;
84 nice_candidate_free (candidate
);
87 if (cmp
->restart_candidate
)
88 nice_candidate_free (cmp
->restart_candidate
),
89 cmp
->restart_candidate
= NULL
;
91 for (i
= cmp
->sockets
; i
; i
= i
->next
) {
92 NiceSocket
*udpsocket
= i
->data
;
93 nice_socket_free (udpsocket
);
96 for (i
= cmp
->gsources
; i
; i
= i
->next
) {
97 GSource
*source
= i
->data
;
98 g_source_destroy (source
);
99 g_source_unref (source
);
102 for (i
= cmp
->incoming_checks
; i
; i
= i
->next
) {
103 IncomingCheck
*icheck
= i
->data
;
104 g_free (icheck
->username
);
105 g_slice_free (IncomingCheck
, icheck
);
108 g_slist_free (cmp
->local_candidates
);
109 g_slist_free (cmp
->remote_candidates
);
110 g_slist_free (cmp
->sockets
);
111 g_slist_free (cmp
->gsources
);
112 g_slist_free (cmp
->incoming_checks
);
114 for (item
= cmp
->turn_servers
; item
; item
= g_list_next (item
)) {
115 TurnServer
*turn
= item
->data
;
116 g_free (turn
->username
);
117 g_free (turn
->password
);
118 g_slice_free (TurnServer
, turn
);
120 g_list_free (cmp
->turn_servers
);
122 if (cmp
->selected_pair
.keepalive
.tick_source
!= NULL
) {
123 g_source_destroy (cmp
->selected_pair
.keepalive
.tick_source
);
124 g_source_unref (cmp
->selected_pair
.keepalive
.tick_source
);
125 cmp
->selected_pair
.keepalive
.tick_source
= NULL
;
128 if (cmp
->tcp_clock
) {
129 g_source_destroy (cmp
->tcp_clock
);
130 g_source_unref (cmp
->tcp_clock
);
131 cmp
->tcp_clock
= NULL
;
134 pseudo_tcp_socket_close (cmp
->tcp
, TRUE
);
135 g_object_unref (cmp
->tcp
);
138 if (cmp
->tcp_data
!= NULL
) {
139 g_slice_free (TcpUserData
, cmp
->tcp_data
);
140 cmp
->tcp_data
= NULL
;
143 if (cmp
->ctx
!= NULL
) {
144 g_main_context_unref (cmp
->ctx
);
148 g_slice_free (Component
, cmp
);
152 * Finds a candidate pair that has matching foundation ids.
154 * @return TRUE if pair found, pointer to pair stored at 'pair'
157 component_find_pair (Component
*cmp
, NiceAgent
*agent
, const gchar
*lfoundation
, const gchar
*rfoundation
, CandidatePair
*pair
)
160 CandidatePair result
;
162 memset (&result
, 0, sizeof(result
));
164 for (i
= cmp
->local_candidates
; i
; i
= i
->next
) {
165 NiceCandidate
*candidate
= i
->data
;
166 if (strncmp (candidate
->foundation
, lfoundation
, NICE_CANDIDATE_MAX_FOUNDATION
) == 0) {
167 result
.local
= candidate
;
172 for (i
= cmp
->remote_candidates
; i
; i
= i
->next
) {
173 NiceCandidate
*candidate
= i
->data
;
174 if (strncmp (candidate
->foundation
, rfoundation
, NICE_CANDIDATE_MAX_FOUNDATION
) == 0) {
175 result
.remote
= candidate
;
180 if (result
.local
&& result
.remote
) {
181 result
.priority
= agent_candidate_pair_priority (agent
, result
.local
, result
.remote
);
191 * Resets the component state to that of a ICE restarted
195 component_restart (Component
*cmp
)
199 for (i
= cmp
->remote_candidates
; i
; i
= i
->next
) {
200 NiceCandidate
*candidate
= i
->data
;
202 /* note: do not remove the remote candidate that is
203 * currently part of the 'selected pair', see ICE
204 * 9.1.1.1. "ICE Restarts" (ID-19) */
205 if (candidate
== cmp
->selected_pair
.remote
) {
206 if (cmp
->restart_candidate
)
207 nice_candidate_free (cmp
->restart_candidate
);
208 cmp
->restart_candidate
= candidate
;
211 nice_candidate_free (candidate
);
213 g_slist_free (cmp
->remote_candidates
),
214 cmp
->remote_candidates
= NULL
;
216 for (i
= cmp
->incoming_checks
; i
; i
= i
->next
) {
217 IncomingCheck
*icheck
= i
->data
;
218 g_free (icheck
->username
);
219 g_slice_free (IncomingCheck
, icheck
);
221 g_slist_free (cmp
->incoming_checks
);
222 cmp
->incoming_checks
= NULL
;
224 /* note: component state managed by agent */
230 * Changes the selected pair for the component to 'pair'. Does not
231 * emit the "selected-pair-changed" signal.
233 void component_update_selected_pair (Component
*component
, const CandidatePair
*pair
)
235 g_assert (component
);
237 nice_debug ("setting SELECTED PAIR for component %u: %s:%s (prio:%"
238 G_GUINT64_FORMAT
").", component
->id
, pair
->local
->foundation
,
239 pair
->remote
->foundation
, pair
->priority
);
241 if (component
->selected_pair
.keepalive
.tick_source
!= NULL
) {
242 g_source_destroy (component
->selected_pair
.keepalive
.tick_source
);
243 g_source_unref (component
->selected_pair
.keepalive
.tick_source
);
244 component
->selected_pair
.keepalive
.tick_source
= NULL
;
247 memset (&component
->selected_pair
, 0, sizeof(CandidatePair
));
249 component
->selected_pair
.local
= pair
->local
;
250 component
->selected_pair
.remote
= pair
->remote
;
251 component
->selected_pair
.priority
= pair
->priority
;
256 * Finds a remote candidate with matching address and
259 * @return pointer to candidate or NULL if not found
262 component_find_remote_candidate (const Component
*component
, const NiceAddress
*addr
, NiceCandidateTransport transport
)
266 for (i
= component
->remote_candidates
; i
; i
= i
->next
) {
267 NiceCandidate
*candidate
= i
->data
;
269 if (nice_address_equal(&candidate
->addr
, addr
) &&
270 candidate
->transport
== transport
)
279 * Sets the desired remote candidate as the selected pair
281 * It will start sending on the highest priority pair available with
286 component_set_selected_remote_candidate (NiceAgent
*agent
, Component
*component
,
287 NiceCandidate
*candidate
)
289 NiceCandidate
*local
= NULL
;
290 NiceCandidate
*remote
= NULL
;
291 guint64 priority
= 0;
294 for (item
= component
->local_candidates
; item
; item
= g_slist_next (item
)) {
295 NiceCandidate
*tmp
= item
->data
;
296 guint64 tmp_prio
= 0;
298 if (tmp
->transport
!= candidate
->transport
||
299 tmp
->addr
.s
.addr
.sa_family
!= candidate
->addr
.s
.addr
.sa_family
||
300 tmp
->type
!= NICE_CANDIDATE_TYPE_HOST
)
303 tmp_prio
= agent_candidate_pair_priority (agent
, tmp
, candidate
);
305 if (tmp_prio
> priority
) {
314 remote
= component_find_remote_candidate (component
, &candidate
->addr
,
315 candidate
->transport
);
318 remote
= nice_candidate_copy (candidate
);
319 component
->remote_candidates
= g_slist_append (component
->remote_candidates
,
321 agent_signal_new_remote_candidate (agent
, remote
);
324 if (component
->selected_pair
.keepalive
.tick_source
!= NULL
) {
325 g_source_destroy (component
->selected_pair
.keepalive
.tick_source
);
326 g_source_unref (component
->selected_pair
.keepalive
.tick_source
);
327 component
->selected_pair
.keepalive
.tick_source
= NULL
;
330 memset (&component
->selected_pair
, 0, sizeof(CandidatePair
));
331 component
->selected_pair
.local
= local
;
332 component
->selected_pair
.remote
= remote
;
333 component
->selected_pair
.priority
= priority
;