component.c 9.15 KB
Newer Older
1 2 3
/*
 * This file is part of the Nice GLib ICE library.
 *
4 5 6
 * (C) 2006-2009 Collabora Ltd.
 *  Contact: Youness Alaoui
 * (C) 2006-2009 Nokia Corporation. All rights reserved.
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *  Contact: Kai Vehmanen
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the Nice GLib ICE library.
 *
 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
 * Corporation. All Rights Reserved.
 *
 * Contributors:
 *   Dafydd Harries, Collabora Ltd.
26
 *   Youness Alaoui, Collabora Ltd.
27
 *   Kai Vehmanen, Nokia
28 29 30 31 32 33 34 35 36 37 38
 *
 * Alternatively, the contents of this file may be used under the terms of the
 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
 * case the provisions of LGPL are applicable instead of those above. If you
 * wish to allow use of your version of this file only under the terms of the
 * LGPL and not to allow others to use your version of this file under the
 * MPL, indicate your decision by deleting the provisions above and replace
 * them with the notice and other provisions required by the LGPL. If you do
 * not delete the provisions above, a recipient may use your version of this
 * file under either the MPL or the LGPL.
 */
39

40
/*
41 42 43 44 45 46 47 48
 * @file component.c
 * @brief ICE component functions
 */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

49 50
#include <string.h>

51 52
#include "debug.h"

53
#include "component.h"
54
#include "agent-priv.h"
55 56

Component *
57
component_new (guint id)
58 59 60 61
{
  Component *component;

  component = g_slice_new0 (Component);
62
  component->id = id;
63 64
  component->state = NICE_COMPONENT_STATE_DISCONNECTED;
  component->restart_candidate = NULL;
65 66
  component->tcp = NULL;

67 68 69 70 71 72 73 74
  return component;
}


void
component_free (Component *cmp)
{
  GSList *i;
75
  GList *item;
76

77 78 79 80
  for (i = cmp->local_candidates; i; i = i->next) {
    NiceCandidate *candidate = i->data;
    nice_candidate_free (candidate);
  }
81

82 83 84 85
  for (i = cmp->remote_candidates; i; i = i->next) {
    NiceCandidate *candidate = i->data;
    nice_candidate_free (candidate);
  }
86

87 88 89 90
  if (cmp->restart_candidate)
    nice_candidate_free (cmp->restart_candidate),
      cmp->restart_candidate = NULL;

91
  for (i = cmp->sockets; i; i = i->next) {
92 93
    NiceSocket *udpsocket = i->data;
    nice_socket_free (udpsocket);
94
  }
95

96 97 98
  for (i = cmp->gsources; i; i = i->next) {
    GSource *source = i->data;
    g_source_destroy (source);
99
    g_source_unref (source);
100
  }
101 102 103
 
  for (i = cmp->incoming_checks; i; i = i->next) {
    IncomingCheck *icheck = i->data;
104
    g_free (icheck->username);
105 106
    g_slice_free (IncomingCheck, icheck);
  }
107 108 109

  g_slist_free (cmp->local_candidates);
  g_slist_free (cmp->remote_candidates);
110
  g_slist_free (cmp->sockets);
Olivier Crête's avatar
Olivier Crête committed
111
  g_slist_free (cmp->gsources);
112
  g_slist_free (cmp->incoming_checks);
113

114 115 116 117 118 119 120
  for (item = cmp->turn_servers; item; item = g_list_next (item)) {
    TurnServer *turn = item->data;
    g_free (turn->username);
    g_free (turn->password);
    g_slice_free (TurnServer, turn);
  }
  g_list_free (cmp->turn_servers);
121

122 123 124 125 126 127
  if (cmp->selected_pair.keepalive.tick_source != NULL) {
    g_source_destroy (cmp->selected_pair.keepalive.tick_source);
    g_source_unref (cmp->selected_pair.keepalive.tick_source);
    cmp->selected_pair.keepalive.tick_source = NULL;
  }

128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
  if (cmp->tcp_clock) {
    g_source_destroy (cmp->tcp_clock);
    g_source_unref (cmp->tcp_clock);
    cmp->tcp_clock = NULL;
  }
  if (cmp->tcp) {
    pseudo_tcp_socket_close (cmp->tcp, TRUE);
    g_object_unref (cmp->tcp);
    cmp->tcp = NULL;
  }
  if (cmp->tcp_data != NULL) {
    g_slice_free (TcpUserData, cmp->tcp_data);
    cmp->tcp_data = NULL;
  }

143 144 145 146 147
  if (cmp->ctx != NULL) {
    g_main_context_unref (cmp->ctx);
    cmp->ctx = NULL;
  }

148 149 150
  g_slice_free (Component, cmp);
}

151
/*
152 153 154 155 156 157 158 159
 * Finds a candidate pair that has matching foundation ids.
 *
 * @return TRUE if pair found, pointer to pair stored at 'pair'
 */
gboolean
component_find_pair (Component *cmp, NiceAgent *agent, const gchar *lfoundation, const gchar *rfoundation, CandidatePair *pair)
{
  GSList *i;
160 161 162
  CandidatePair result;

  memset (&result, 0, sizeof(result));
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

  for (i = cmp->local_candidates; i; i = i->next) {
    NiceCandidate *candidate = i->data;
    if (strncmp (candidate->foundation, lfoundation, NICE_CANDIDATE_MAX_FOUNDATION) == 0) {
      result.local = candidate;
      break;
    }
  }

  for (i = cmp->remote_candidates; i; i = i->next) {
    NiceCandidate *candidate = i->data;
    if (strncmp (candidate->foundation, rfoundation, NICE_CANDIDATE_MAX_FOUNDATION) == 0) {
      result.remote = candidate;
      break;
    }
  }

  if (result.local && result.remote) {
    result.priority = agent_candidate_pair_priority (agent, result.local, result.remote);
    if (pair)
      *pair = result;
    return TRUE;
  }

  return FALSE;
}

190
/*
191 192 193 194 195 196 197 198 199 200 201 202 203
 * Resets the component state to that of a ICE restarted
 * session.
 */
gboolean
component_restart (Component *cmp)
{
  GSList *i;

  for (i = cmp->remote_candidates; i; i = i->next) {
    NiceCandidate *candidate = i->data;

    /* note: do not remove the remote candidate that is
     *       currently part of the 'selected pair', see ICE
204
     *       9.1.1.1. "ICE Restarts" (ID-19) */
205 206 207 208 209 210 211 212 213 214 215
    if (candidate == cmp->selected_pair.remote) {
      if (cmp->restart_candidate)
	nice_candidate_free (cmp->restart_candidate);
      cmp->restart_candidate = candidate;
    }
    else 
      nice_candidate_free (candidate);
  }
  g_slist_free (cmp->remote_candidates),
    cmp->remote_candidates = NULL;

216 217
  for (i = cmp->incoming_checks; i; i = i->next) {
    IncomingCheck *icheck = i->data;
218
    g_free (icheck->username);
219 220
    g_slice_free (IncomingCheck, icheck);
  }
221 222
  g_slist_free (cmp->incoming_checks);
  cmp->incoming_checks = NULL;
223

224 225 226 227
  /* note: component state managed by agent */

  return TRUE;
}
228

229
/*
230 231 232 233 234 235 236
 * Changes the selected pair for the component to 'pair'. Does not
 * emit the "selected-pair-changed" signal.
 */ 
void component_update_selected_pair (Component *component, const CandidatePair *pair)
{
  g_assert (component);
  g_assert (pair);
237 238 239
  nice_debug ("setting SELECTED PAIR for component %u: %s:%s (prio:%"
      G_GUINT64_FORMAT ").", component->id, pair->local->foundation,
      pair->remote->foundation, pair->priority);
240 241 242 243 244 245 246 247 248

  if (component->selected_pair.keepalive.tick_source != NULL) {
    g_source_destroy (component->selected_pair.keepalive.tick_source);
    g_source_unref (component->selected_pair.keepalive.tick_source);
    component->selected_pair.keepalive.tick_source = NULL;
  }

  memset (&component->selected_pair, 0, sizeof(CandidatePair));

249 250 251
  component->selected_pair.local = pair->local;
  component->selected_pair.remote = pair->remote;
  component->selected_pair.priority = pair->priority;
252

253
}
254

255
/*
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
 * Finds a remote candidate with matching address and 
 * transport.
 *
 * @return pointer to candidate or NULL if not found
 */
NiceCandidate *
component_find_remote_candidate (const Component *component, const NiceAddress *addr, NiceCandidateTransport transport)
{
  GSList *i;

  for (i = component->remote_candidates; i; i = i->next) {
    NiceCandidate *candidate = i->data;

    if (nice_address_equal(&candidate->addr, addr) &&
	candidate->transport == transport)
      return candidate;

  }
  
  return NULL;
}
277 278 279 280 281 282 283 284 285 286 287 288 289 290

/*
 * Sets the desired remote candidate as the selected pair
 *
 * It will start sending on the highest priority pair available with
 * this candidate.
 */

NiceCandidate *
component_set_selected_remote_candidate (NiceAgent *agent, Component *component,
    NiceCandidate *candidate)
{
  NiceCandidate *local = NULL;
  NiceCandidate *remote = NULL;
291
  guint64 priority = 0;
292 293 294 295
  GSList *item = NULL;

  for (item = component->local_candidates; item; item = g_slist_next (item)) {
    NiceCandidate *tmp = item->data;
296
    guint64 tmp_prio = 0;
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318

    if (tmp->transport != candidate->transport ||
	tmp->addr.s.addr.sa_family != candidate->addr.s.addr.sa_family ||
        tmp->type != NICE_CANDIDATE_TYPE_HOST)
      continue;

    tmp_prio = agent_candidate_pair_priority (agent, tmp, candidate);

    if (tmp_prio > priority) {
      priority = tmp_prio;
      local = tmp;
    }
  }

  if (local == NULL)
    return NULL;

  remote = component_find_remote_candidate (component, &candidate->addr,
      candidate->transport);

  if (!remote) {
    remote = nice_candidate_copy (candidate);
319 320 321
    component->remote_candidates = g_slist_append (component->remote_candidates,
        remote);
    agent_signal_new_remote_candidate (agent, remote);
322 323
  }

324 325 326 327 328 329 330
  if (component->selected_pair.keepalive.tick_source != NULL) {
    g_source_destroy (component->selected_pair.keepalive.tick_source);
    g_source_unref (component->selected_pair.keepalive.tick_source);
    component->selected_pair.keepalive.tick_source = NULL;
  }

  memset (&component->selected_pair, 0, sizeof(CandidatePair));
331 332 333 334 335 336
  component->selected_pair.local = local;
  component->selected_pair.remote = remote;
  component->selected_pair.priority = priority;

  return local;
}