Version 0.0.10
[sipe-libnice.git] / agent / component.c
blob329016d43a1a20feb57d13b9cc78d66f78705b04
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2006, 2007 Collabora Ltd.
5 * Contact: Dafydd Harries
6 * (C) 2006, 2007 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
17 * License.
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.
24 * Contributors:
25 * Dafydd Harries, Collabora Ltd.
26 * Kai Vehmanen, Nokia
28 * Alternatively, the contents of this file may be used under the terms of the
29 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
30 * case the provisions of LGPL are applicable instead of those above. If you
31 * wish to allow use of your version of this file only under the terms of the
32 * LGPL and not to allow others to use your version of this file under the
33 * MPL, indicate your decision by deleting the provisions above and replace
34 * them with the notice and other provisions required by the LGPL. If you do
35 * not delete the provisions above, a recipient may use your version of this
36 * file under either the MPL or the LGPL.
40 * @file component.c
41 * @brief ICE component functions
44 #ifdef HAVE_CONFIG_H
45 # include <config.h>
46 #endif
48 #include <string.h>
50 #include "debug.h"
52 #include "component.h"
53 #include "agent-priv.h"
55 Component *
56 component_new (
57 G_GNUC_UNUSED
58 guint id)
60 Component *component;
62 component = g_slice_new0 (Component);
63 component->id = id;
64 component->state = NICE_COMPONENT_STATE_DISCONNECTED;
65 component->restart_candidate = NULL;
66 return component;
70 void
71 component_free (Component *cmp)
73 GSList *i;
74 GList *item;
76 for (i = cmp->local_candidates; i; i = i->next) {
77 NiceCandidate *candidate = i->data;
78 nice_candidate_free (candidate);
81 for (i = cmp->remote_candidates; i; i = i->next) {
82 NiceCandidate *candidate = i->data;
83 nice_candidate_free (candidate);
86 if (cmp->restart_candidate)
87 nice_candidate_free (cmp->restart_candidate),
88 cmp->restart_candidate = NULL;
90 for (i = cmp->sockets; i; i = i->next) {
91 NiceSocket *udpsocket = i->data;
92 nice_socket_free (udpsocket);
95 for (i = cmp->gsources; i; i = i->next) {
96 GSource *source = i->data;
97 g_source_destroy (source);
98 g_source_unref (source);
101 for (i = cmp->incoming_checks; i; i = i->next) {
102 IncomingCheck *icheck = i->data;
103 g_free (icheck->username);
104 g_slice_free (IncomingCheck, icheck);
107 g_slist_free (cmp->local_candidates);
108 g_slist_free (cmp->remote_candidates);
109 g_slist_free (cmp->sockets);
110 g_slist_free (cmp->gsources);
111 g_slist_free (cmp->incoming_checks);
113 for (item = cmp->turn_servers; item; item = g_list_next (item)) {
114 TurnServer *turn = item->data;
115 g_free (turn->username);
116 g_free (turn->password);
117 g_slice_free (TurnServer, turn);
119 g_list_free (cmp->turn_servers);
121 if (cmp->selected_pair.keepalive.tick_source != NULL) {
122 g_source_destroy (cmp->selected_pair.keepalive.tick_source);
123 g_source_unref (cmp->selected_pair.keepalive.tick_source);
124 cmp->selected_pair.keepalive.tick_source = NULL;
127 g_slice_free (Component, cmp);
131 * Finds a candidate pair that has matching foundation ids.
133 * @return TRUE if pair found, pointer to pair stored at 'pair'
135 gboolean
136 component_find_pair (Component *cmp, NiceAgent *agent, const gchar *lfoundation, const gchar *rfoundation, CandidatePair *pair)
138 GSList *i;
139 CandidatePair result;
141 memset (&result, 0, sizeof(result));
143 for (i = cmp->local_candidates; i; i = i->next) {
144 NiceCandidate *candidate = i->data;
145 if (strncmp (candidate->foundation, lfoundation, NICE_CANDIDATE_MAX_FOUNDATION) == 0) {
146 result.local = candidate;
147 break;
151 for (i = cmp->remote_candidates; i; i = i->next) {
152 NiceCandidate *candidate = i->data;
153 if (strncmp (candidate->foundation, rfoundation, NICE_CANDIDATE_MAX_FOUNDATION) == 0) {
154 result.remote = candidate;
155 break;
159 if (result.local && result.remote) {
160 result.priority = agent_candidate_pair_priority (agent, result.local, result.remote);
161 if (pair)
162 *pair = result;
163 return TRUE;
166 return FALSE;
170 * Resets the component state to that of a ICE restarted
171 * session.
173 gboolean
174 component_restart (Component *cmp)
176 GSList *i;
178 for (i = cmp->remote_candidates; i; i = i->next) {
179 NiceCandidate *candidate = i->data;
181 /* note: do not remove the remote candidate that is
182 * currently part of the 'selected pair', see ICE
183 * 9.1.1.1. "ICE Restarts" (ID-19) */
184 if (candidate == cmp->selected_pair.remote) {
185 if (cmp->restart_candidate)
186 nice_candidate_free (cmp->restart_candidate);
187 cmp->restart_candidate = candidate;
189 else
190 nice_candidate_free (candidate);
192 g_slist_free (cmp->remote_candidates),
193 cmp->remote_candidates = NULL;
195 for (i = cmp->incoming_checks; i; i = i->next) {
196 IncomingCheck *icheck = i->data;
197 g_free (icheck->username);
198 g_slice_free (IncomingCheck, icheck);
200 g_slist_free (cmp->incoming_checks);
201 cmp->incoming_checks = NULL;
203 /* note: component state managed by agent */
205 return TRUE;
209 * Changes the selected pair for the component to 'pair'. Does not
210 * emit the "selected-pair-changed" signal.
212 void component_update_selected_pair (Component *component, const CandidatePair *pair)
214 g_assert (component);
215 g_assert (pair);
216 nice_debug ("setting SELECTED PAIR for component %u: %s:%s (prio:%lu).",
217 component->id, pair->local->foundation, pair->remote->foundation, (long unsigned)pair->priority);
219 if (component->selected_pair.keepalive.tick_source != NULL) {
220 g_source_destroy (component->selected_pair.keepalive.tick_source);
221 g_source_unref (component->selected_pair.keepalive.tick_source);
222 component->selected_pair.keepalive.tick_source = NULL;
225 memset (&component->selected_pair, 0, sizeof(CandidatePair));
227 component->selected_pair.local = pair->local;
228 component->selected_pair.remote = pair->remote;
229 component->selected_pair.priority = pair->priority;
234 * Finds a remote candidate with matching address and
235 * transport.
237 * @return pointer to candidate or NULL if not found
239 NiceCandidate *
240 component_find_remote_candidate (const Component *component, const NiceAddress *addr, NiceCandidateTransport transport)
242 GSList *i;
244 for (i = component->remote_candidates; i; i = i->next) {
245 NiceCandidate *candidate = i->data;
247 if (nice_address_equal(&candidate->addr, addr) &&
248 candidate->transport == transport)
249 return candidate;
253 return NULL;
257 * Sets the desired remote candidate as the selected pair
259 * It will start sending on the highest priority pair available with
260 * this candidate.
263 NiceCandidate *
264 component_set_selected_remote_candidate (NiceAgent *agent, Component *component,
265 NiceCandidate *candidate)
267 NiceCandidate *local = NULL;
268 NiceCandidate *remote = NULL;
269 guint32 priority = 0;
270 GSList *item = NULL;
272 for (item = component->local_candidates; item; item = g_slist_next (item)) {
273 NiceCandidate *tmp = item->data;
274 guint32 tmp_prio = 0;
276 if (tmp->transport != candidate->transport ||
277 tmp->addr.s.addr.sa_family != candidate->addr.s.addr.sa_family ||
278 tmp->type != NICE_CANDIDATE_TYPE_HOST)
279 continue;
281 tmp_prio = agent_candidate_pair_priority (agent, tmp, candidate);
283 if (tmp_prio > priority) {
284 priority = tmp_prio;
285 local = tmp;
289 if (local == NULL)
290 return NULL;
292 remote = component_find_remote_candidate (component, &candidate->addr,
293 candidate->transport);
295 if (!remote) {
296 GSList *modified_list = NULL;
298 remote = nice_candidate_copy (candidate);
300 modified_list = g_slist_append (component->remote_candidates,
301 remote);
302 if (modified_list) {
303 component->remote_candidates = modified_list;
304 agent_signal_new_remote_candidate (agent, remote);
306 else { /* error: memory alloc / list */
307 nice_candidate_free (remote), remote = NULL;
308 return NULL;
312 if (component->selected_pair.keepalive.tick_source != NULL) {
313 g_source_destroy (component->selected_pair.keepalive.tick_source);
314 g_source_unref (component->selected_pair.keepalive.tick_source);
315 component->selected_pair.keepalive.tick_source = NULL;
318 memset (&component->selected_pair, 0, sizeof(CandidatePair));
319 component->selected_pair.local = local;
320 component->selected_pair.remote = remote;
321 component->selected_pair.priority = priority;
323 return local;