component.c 48 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
 * @file component.c
 * @brief ICE component functions
 */

45
46
47
48
49
/* Simple tracking for the number of alive components. These must be accessed
 * atomically. */
static volatile unsigned int n_components_created = 0;
static volatile unsigned int n_components_destroyed = 0;

50
51
52
53
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

54
55
#include <string.h>

56
57
#include "debug.h"

58
#include "component.h"
59
#include "discovery.h"
60
#include "agent-priv.h"
61

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
G_DEFINE_TYPE (NiceComponent, nice_component, G_TYPE_OBJECT);

typedef enum {
  PROP_ID = 1,
  PROP_AGENT,
  PROP_STREAM,
} NiceComponentProperty;

static void
nice_component_constructed (GObject *obj);
static void
nice_component_get_property (GObject *obj,
    guint property_id, GValue *value, GParamSpec *pspec);
static void
nice_component_set_property (GObject *obj,
    guint property_id, const GValue *value, GParamSpec *pspec);
static void
nice_component_finalize (GObject *obj);
80

81
static void
82
nice_component_schedule_io_callback (NiceComponent *component);
83
static void
84
nice_component_deschedule_io_callback (NiceComponent *component);
85
86
87
88
static void
nice_component_detach_socket (NiceComponent *component, NiceSocket *nicesock);
static void
nice_component_clear_selected_pair (NiceComponent *component);
89
90


91
92
93
94
95
96
97
void
incoming_check_free (IncomingCheck *icheck)
{
  g_free (icheck->username);
  g_slice_free (IncomingCheck, icheck);
}

98
/* Must *not* take the agent lock, since it’s called from within
99
 * nice_component_set_io_context(), which holds the Component’s I/O lock. */
100
101
102
103
104
static void
socket_source_attach (SocketSource *socket_source, GMainContext *context)
{
  GSource *source;

Olivier Crête's avatar
Olivier Crête committed
105
106
107
  if (socket_source->socket->fileno == NULL)
    return;

108
109
110
111
112
113
114
  /* Do not create a GSource for UDP turn socket, because it
   * would duplicate the packets already received on the base
   * UDP socket.
   */
  if (socket_source->socket->type == NICE_SOCKET_TYPE_UDP_TURN)
    return;

115
116
117
  /* Create a source. */
  source = g_socket_create_source (socket_source->socket->fileno,
      G_IO_IN, NULL);
118
  g_source_set_callback (source, (GSourceFunc) G_CALLBACK (component_io_cb),
119
120
121
122
123
124
125
126
127
128
129
130
      socket_source, NULL);

  /* Add the source. */
  nice_debug ("Attaching source %p (socket %p, FD %d) to context %p", source,
      socket_source->socket, g_socket_get_fd (socket_source->socket->fileno),
      context);

  g_assert (socket_source->source == NULL);
  socket_source->source = source;
  g_source_attach (source, context);
}

131
132
133
static void
socket_source_detach (SocketSource *source)
{
134
135
136
137
138
139
  nice_debug ("Detaching source %p (socket %p, FD %d) from context %p",
      source->source, source->socket,
      (source->socket->fileno != NULL) ?
          g_socket_get_fd (source->socket->fileno) : 0,
      (source->source != NULL) ? g_source_get_context (source->source) : 0);

140
141
142
143
144
145
146
147
148
149
150
  if (source->source != NULL) {
    g_source_destroy (source->source);
    g_source_unref (source->source);
  }
  source->source = NULL;
}

static void
socket_source_free (SocketSource *source)
{
  socket_source_detach (source);
151
  nice_socket_free (source->socket);
152
153
154
155

  g_slice_free (SocketSource, source);
}

156
157
NiceComponent *
nice_component_new (guint id, NiceAgent *agent, NiceStream *stream)
158
{
159
160
161
162
163
  return g_object_new (NICE_TYPE_COMPONENT,
                       "id", id,
                       "agent", agent,
                       "stream", stream,
                       NULL);
164
165
}

166
void
167
168
nice_component_remove_socket (NiceAgent *agent, NiceComponent *cmp,
    NiceSocket *nsocket)
169
170
{
  GSList *i;
171
172
173
  NiceStream *stream;

  stream = agent_find_stream (agent, cmp->stream_id);
174

175
176
177
178
  discovery_prune_socket (agent, nsocket);
  if (stream)
    conn_check_prune_socket (agent, stream, cmp, nsocket);

179
180
181
182
183
184
185
186
187
188
189
  for (i = cmp->local_candidates; i;) {
    NiceCandidate *candidate = i->data;
    GSList *next = i->next;

    if (!nice_socket_is_based_on (candidate->sockptr, nsocket)) {
      i = next;
      continue;
    }

    if (candidate == cmp->selected_pair.local) {
      nice_component_clear_selected_pair (cmp);
190
      agent_signal_component_state_change (agent, cmp->stream_id,
191
192
193
          cmp->id, NICE_COMPONENT_STATE_FAILED);
    }

194
    refresh_prune_candidate (agent, candidate);
195
196
    if (candidate->sockptr != nsocket && stream) {
      discovery_prune_socket (agent, candidate->sockptr);
197
      conn_check_prune_socket (agent, stream, cmp,
198
199
200
          candidate->sockptr);
      nice_component_detach_socket (cmp, candidate->sockptr);
    }
201
    agent_remove_local_candidate (agent, candidate);
202
203
204
205
206
207
    nice_candidate_free (candidate);

    cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, i);
    i = next;
  }

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
  /* The nsocket to be removed may also come from a
   * peer-reflexive remote candidate
   */
  for (i = cmp->remote_candidates; i;) {
    NiceCandidate *candidate = i->data;
    GSList *next = i->next;

    if (candidate->sockptr != nsocket) {
      i = next;
      continue;
    }

    if (candidate == cmp->selected_pair.remote) {
      nice_component_clear_selected_pair (cmp);
      agent_signal_component_state_change (agent, cmp->stream_id,
          cmp->id, NICE_COMPONENT_STATE_FAILED);
    }

    if (stream)
      conn_check_prune_socket (agent, stream, cmp, candidate->sockptr);

    nice_candidate_free (candidate);

    cmp->remote_candidates = g_slist_delete_link (cmp->remote_candidates, i);
    i = next;
  }

235
236
237
  nice_component_detach_socket (cmp, nsocket);
}

238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
static gboolean
on_candidate_refreshes_pruned (NiceAgent *agent, NiceCandidate *candidate)
{
  NiceComponent *component;

  if (agent_find_component (agent, candidate->stream_id,
      candidate->component_id, NULL, &component)) {
    nice_component_detach_socket (component, candidate->sockptr);
  }

  nice_candidate_free (candidate);

  return G_SOURCE_REMOVE;
}

253
void
254
nice_component_clean_turn_servers (NiceAgent *agent, NiceComponent *cmp)
255
{
256
  GSList *i;
257
  GSList *relay_candidates = NULL;
258
259
260
  NiceStream *stream;

  stream = agent_find_stream (agent, cmp->stream_id);
261

262
  g_list_free_full (cmp->turn_servers, (GDestroyNotify) turn_server_unref);
263
  cmp->turn_servers = NULL;
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284

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

    if (candidate->type != NICE_CANDIDATE_TYPE_RELAYED) {
      i = next;
      continue;
    }

    /* note: do not remove the remote candidate that is
     *       currently part of the 'selected pair', see ICE
     *       9.1.1.1. "ICE Restarts" (ID-19)
     *
     * So what we do instead is that we put the selected candidate
     * in a special location and keep it "alive" that way. This is
     * especially important for TURN, because refresh requests to the
     * server need to keep happening.
     */
    if (candidate == cmp->selected_pair.local) {
      if (cmp->turn_candidate) {
285
        relay_candidates = g_slist_append(relay_candidates, cmp->turn_candidate);
286
287
288
289
290
291
292
      }
      /* Bring the priority down to 0, so that it will be replaced
       * on the new run.
       */
      cmp->selected_pair.priority = 0;
      cmp->turn_candidate = candidate;
    } else {
293
      agent_remove_local_candidate (agent, candidate);
294
      relay_candidates = g_slist_append(relay_candidates, candidate);
295
296
297
298
    }
    cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, i);
    i = next;
  }
299
300
301
302
303
304
305
306

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

    discovery_prune_socket (agent, candidate->sockptr);
    if (stream) {
      conn_check_prune_socket (agent, stream, cmp, candidate->sockptr);
    }
307
308
309

    refresh_prune_candidate_async (agent, candidate,
        (NiceTimeoutLockedCallback) on_candidate_refreshes_pruned);
310
  }
311
312
}

313
static void
314
nice_component_clear_selected_pair (NiceComponent *component)
315
316
317
318
319
320
321
322
323
324
{
  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));
}

325
326
/* Must be called with the agent lock held as it touches internal Component
 * state. */
327
void
328
nice_component_close (NiceAgent *agent, NiceComponent *cmp)
329
{
330
  IOCallbackData *data;
331
  GOutputVector *vec;
332
  IncomingCheck *c;
333

334
335
336
  /* Start closing the pseudo-TCP socket first. FIXME: There is a very big and
   * reliably triggerable race here. pseudo_tcp_socket_close() does not block
   * on the socket closing — it only sends the first packet of the FIN
337
   * handshake. nice_component_close() will immediately afterwards close the
338
339
340
341
   * underlying component sockets, aborting the handshake.
   *
   * On the principle that starting the FIN handshake is better than not
   * starting it, even if it’s later truncated, call pseudo_tcp_socket_close().
342
343
   * A long-term fix is needed in the form of making nice_component_close() (and
   * all its callers) async, so we can properly block on closure. */
344
345
346
347
  if (cmp->tcp) {
    pseudo_tcp_socket_close (cmp->tcp, TRUE);
  }

348
349
350
351
  if (cmp->restart_candidate)
    nice_candidate_free (cmp->restart_candidate),
      cmp->restart_candidate = NULL;

352
353
354
355
  if (cmp->turn_candidate)
    nice_candidate_free (cmp->turn_candidate),
        cmp->turn_candidate = NULL;

356
  while (cmp->local_candidates) {
357
    agent_remove_local_candidate (agent, cmp->local_candidates->data);
358
359
360
361
362
    nice_candidate_free (cmp->local_candidates->data);
    cmp->local_candidates = g_slist_delete_link (cmp->local_candidates,
        cmp->local_candidates);
  }

363
364
  g_slist_free_full (cmp->remote_candidates,
      (GDestroyNotify) nice_candidate_free);
365
  cmp->remote_candidates = NULL;
366
  nice_component_free_socket_sources (cmp);
367
368
369

  while ((c = g_queue_pop_head (&cmp->incoming_checks)))
    incoming_check_free (c);
370

371
  nice_component_clean_turn_servers (agent, cmp);
372

373
374
375
376
377
  if (cmp->tcp_clock) {
    g_source_destroy (cmp->tcp_clock);
    g_source_unref (cmp->tcp_clock);
    cmp->tcp_clock = NULL;
  }
378
379
380
381
  if (cmp->tcp_writable_cancellable) {
    g_cancellable_cancel (cmp->tcp_writable_cancellable);
    g_clear_object (&cmp->tcp_writable_cancellable);
  }
382

383
384
385
  while ((data = g_queue_pop_head (&cmp->pending_io_messages)) != NULL)
    io_callback_data_free (data);

386
  nice_component_deschedule_io_callback (cmp);
387

388
  g_cancellable_cancel (cmp->stop_cancellable);
389

390
391
392
393
  while ((vec = g_queue_pop_head (&cmp->queued_tcp_packets)) != NULL) {
    g_free ((gpointer) vec->buffer);
    g_slice_free (GOutputVector, vec);
  }
394
}
395

396
/*
397
398
399
400
401
 * Finds a candidate pair that has matching foundation ids.
 *
 * @return TRUE if pair found, pointer to pair stored at 'pair'
 */
gboolean
402
nice_component_find_pair (NiceComponent *cmp, NiceAgent *agent, const gchar *lfoundation, const gchar *rfoundation, CandidatePair *pair)
403
404
{
  GSList *i;
405
  CandidatePair result = { 0, };
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432

  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;
}

433
/*
434
435
436
 * Resets the component state to that of a ICE restarted
 * session.
 */
437
void
438
nice_component_restart (NiceComponent *cmp)
439
440
{
  GSList *i;
441
  IncomingCheck *c;
442
443
444
445

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

446
    /* note: do not remove the remote candidate that is
447
     *       currently part of the 'selected pair', see ICE
448
     *       9.1.1.1. "ICE Restarts" (ID-19) */
449
450
451
452
453
454
455
456
457
458
459
    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;

460
461
  while ((c = g_queue_pop_head (&cmp->incoming_checks)))
    incoming_check_free (c);
462

463
464
465
  /* Reset the priority to 0 to make sure we get a new pair */
  cmp->selected_pair.priority = 0;

466
467
  /* note: component state managed by agent */
}
468

469
/*
470
471
472
 * Changes the selected pair for the component to 'pair'. Does not
 * emit the "selected-pair-changed" signal.
 */ 
473
void
474
nice_component_update_selected_pair (NiceAgent *agent, NiceComponent *component, const CandidatePair *pair)
475
{
476
  NiceStream *stream;
477
  gchar priority[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE];
478

479
480
  g_assert (component);
  g_assert (pair);
481

482
  stream = agent_find_stream (agent, component->stream_id);
483

484
485
486
487
  nice_candidate_pair_priority_to_string (pair->priority, priority);
  nice_debug ("setting SELECTED PAIR for component %u: %s:%s (prio:%s).",
      component->id, pair->local->foundation,
      pair->remote->foundation, priority);
488

489
490
  if (component->selected_pair.local &&
      component->selected_pair.local == component->turn_candidate) {
491
    discovery_prune_socket (agent,
492
        component->turn_candidate->sockptr);
493
    if (stream)
494
      conn_check_prune_socket (agent, stream, component,
495
          component->turn_candidate->sockptr);
496
497
    refresh_prune_candidate_async (agent, component->turn_candidate,
        (NiceTimeoutLockedCallback) on_candidate_refreshes_pruned);
498
499
500
    component->turn_candidate = NULL;
  }

501
  nice_component_clear_selected_pair (component);
502

503
504
505
  component->selected_pair.local = pair->local;
  component->selected_pair.remote = pair->remote;
  component->selected_pair.priority = pair->priority;
506
  component->selected_pair.stun_priority = pair->stun_priority;
507

508
  nice_component_add_valid_candidate (agent, component, pair->remote);
509
}
510

511
/*
512
513
514
515
516
517
 * Finds a remote candidate with matching address and 
 * transport.
 *
 * @return pointer to candidate or NULL if not found
 */
NiceCandidate *
518
nice_component_find_remote_candidate (NiceComponent *component, const NiceAddress *addr, NiceCandidateTransport transport)
519
520
521
522
523
524
525
526
527
528
529
530
531
532
{
  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;
}
533
534
535
536
537
538
539
540
541

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

NiceCandidate *
542
543
nice_component_set_selected_remote_candidate (NiceComponent *component,
    NiceAgent *agent, NiceCandidate *candidate)
544
545
546
{
  NiceCandidate *local = NULL;
  NiceCandidate *remote = NULL;
547
  guint64 priority = 0;
548
549
  GSList *item = NULL;

550
551
  g_assert (candidate != NULL);

552
553
  for (item = component->local_candidates; item; item = g_slist_next (item)) {
    NiceCandidate *tmp = item->data;
554
    guint64 tmp_prio = 0;
555

556
    if (tmp->transport != conn_check_match_transport(candidate->transport) ||
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
	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;

572
  remote = nice_component_find_remote_candidate (component, &candidate->addr,
573
574
575
576
      candidate->transport);

  if (!remote) {
    remote = nice_candidate_copy (candidate);
577
578
579
    component->remote_candidates = g_slist_append (component->remote_candidates,
        remote);
    agent_signal_new_remote_candidate (agent, remote);
580
581
  }

582
  nice_component_clear_selected_pair (component);
583

584
585
586
587
  component->selected_pair.local = local;
  component->selected_pair.remote = remote;
  component->selected_pair.priority = priority;

588
589
590
591
592
  /* Get into fallback mode where packets from any source is accepted once
   * this has been called. This is the expected behavior of pre-ICE SIP.
   */
  component->fallback_mode = TRUE;

593
594
  return local;
}
595
596
597
598
599
600
601
602
603
604

static gint
_find_socket_source (gconstpointer a, gconstpointer b)
{
  const SocketSource *source_a = a;
  const NiceSocket *socket_b = b;

  return (source_a->socket == socket_b) ? 0 : 1;
}

605
606
/* This takes ownership of the socket.
 * It creates and attaches a source to the component’s context. */
607
void
608
nice_component_attach_socket (NiceComponent *component, NiceSocket *nicesock)
609
610
611
612
613
{
  GSList *l;
  SocketSource *socket_source;

  g_assert (component != NULL);
614
  g_assert (nicesock != NULL);
615

616
617
618
  g_assert (component->ctx != NULL);

  /* Find an existing SocketSource in the component which contains @socket, or
619
620
   * create a new one.
   *
621
622
623
   * Whenever a source is added or remove to socket_sources, socket_sources_age
   * must be incremented.
   */
624
  l = g_slist_find_custom (component->socket_sources, nicesock,
625
626
627
628
629
          _find_socket_source);
  if (l != NULL) {
    socket_source = l->data;
  } else {
    socket_source = g_slice_new0 (SocketSource);
630
    socket_source->socket = nicesock;
631
    socket_source->component = component;
632
633
    component->socket_sources =
        g_slist_prepend (component->socket_sources, socket_source);
Olivier Crête's avatar
Olivier Crête committed
634
635
    if (nicesock->fileno != NULL)
      component->socket_sources_age++;
636
637
  }

638
  /* Create and attach a source */
639
640
  nice_debug ("Component %p: Attach source (stream %u).",
      component, component->stream_id);
641
  socket_source_attach (socket_source, component->ctx);
642
643
}

644
645
646
/* Reattaches socket handles of @component to the main context.
 *
 * Must *not* take the agent lock, since it’s called from within
647
 * nice_component_set_io_context(), which holds the Component’s I/O lock. */
648
static void
649
nice_component_reattach_all_sockets (NiceComponent *component)
650
{
651
  GSList *i;
652

653
654
655
656
657
658
  for (i = component->socket_sources; i != NULL; i = i->next) {
    SocketSource *socket_source = i->data;
    nice_debug ("Reattach source %p.", socket_source->source);
    socket_source_detach (socket_source);
    socket_source_attach (socket_source, component->ctx);
  }
659
660
661
}

/**
662
 * nice_component_detach_socket:
663
 * @component: a #NiceComponent
664
665
 * @socket: the socket to detach the source for
 *
666
667
 * Detach the #GSource for the single specified @socket. It also closes it
 * and frees it!
668
669
670
 *
 * If the @socket doesn’t exist in this @component, do nothing.
 */
671
static void
672
nice_component_detach_socket (NiceComponent *component, NiceSocket *nicesock)
673
{
674
675
  GList *l;
  GSList *s;
676
677
  SocketSource *socket_source;

678
  nice_debug ("Detach socket %p.", nicesock);
679

680
  /* Remove the socket from various lists. */
681
  for (l = component->incoming_checks.head; l != NULL;) {
682
    IncomingCheck *icheck = l->data;
683
    GList *next = l->next;
684
685

    if (icheck->local_socket == nicesock) {
686
      g_queue_delete_link (&component->incoming_checks, l);
687
688
689
690
691
692
      incoming_check_free (icheck);
    }

    l = next;
  }

693
  /* Find the SocketSource for the socket. */
694
  s = g_slist_find_custom (component->socket_sources, nicesock,
695
          _find_socket_source);
696
  if (s == NULL)
697
698
699
    return;

  /* Detach the source. */
700
701
  socket_source = s->data;
  component->socket_sources = g_slist_delete_link (component->socket_sources, s);
702
703
704
  component->socket_sources_age++;

  socket_source_free (socket_source);
705
706
707
708
709
}

/*
 * Detaches socket handles of @component from the main context. Leaves the
 * sockets themselves untouched.
710
711
 *
 * Must *not* take the agent lock, since it’s called from within
712
 * nice_component_set_io_context(), which holds the Component’s I/O lock.
713
714
 */
void
715
nice_component_detach_all_sockets (NiceComponent *component)
716
717
718
719
720
{
  GSList *i;

  for (i = component->socket_sources; i != NULL; i = i->next) {
    SocketSource *socket_source = i->data;
721
722
    nice_debug ("Detach source %p, socket %p.", socket_source->source,
        socket_source->socket);
723
724
725
726
727
    socket_source_detach (socket_source);
  }
}

void
728
nice_component_free_socket_sources (NiceComponent *component)
729
{
730
731
  nice_debug ("Free socket sources for component %p.", component);

732
733
734
  g_slist_free_full (component->socket_sources,
      (GDestroyNotify) socket_source_free);
  component->socket_sources = NULL;
735
  component->socket_sources_age++;
736

737
  nice_component_clear_selected_pair (component);
738
}
739

740
GMainContext *
741
nice_component_dup_io_context (NiceComponent *component)
742
{
743
  return g_main_context_ref (component->own_ctx);
744
745
}

746
/* If @context is %NULL, it's own context is used, so component->ctx is always
747
 * guaranteed to be non-%NULL. */
748
void
749
nice_component_set_io_context (NiceComponent *component, GMainContext *context)
750
{
751
752
  g_mutex_lock (&component->io_mutex);

753
  if (component->ctx != context) {
754
    if (context == NULL)
755
      context = g_main_context_ref (component->own_ctx);
756
757
758
    else
      g_main_context_ref (context);

759
    nice_component_detach_all_sockets (component);
760
761
    g_main_context_unref (component->ctx);

762
    component->ctx = context;
763
    nice_component_reattach_all_sockets (component);
764
  }
765

766
767
  g_mutex_unlock (&component->io_mutex);
}
768

769
770
771
/* (func, user_data) and (recv_messages, n_recv_messages) are mutually
 * exclusive. At most one of the two must be specified; if both are NULL, the
 * Component will not receive any data (i.e. reception is paused).
772
773
774
775
776
777
778
 *
 * Apart from during setup, this must always be called with the agent lock held,
 * and the I/O lock released (because it takes the I/O lock itself). Requiring
 * the agent lock to be held means it can’t be called between a packet being
 * dequeued from the kernel buffers in agent.c, and an I/O callback being
 * emitted for it (which could cause data loss if the I/O callback function was
 * unset in that time). */
779
void
780
nice_component_set_io_callback (NiceComponent *component,
781
    NiceAgentRecvFunc func, gpointer user_data,
782
    NiceInputMessage *recv_messages, guint n_recv_messages,
783
    GError **error)
784
{
785
786
  g_assert (func == NULL || recv_messages == NULL);
  g_assert (n_recv_messages == 0 || recv_messages != NULL);
787
788
  g_assert (error == NULL || *error == NULL);

789
  g_mutex_lock (&component->io_mutex);
790
791
792
793

  if (func != NULL) {
    component->io_callback = func;
    component->io_user_data = user_data;
794
795
    component->recv_messages = NULL;
    component->n_recv_messages = 0;
796

797
    nice_component_schedule_io_callback (component);
798
  } else {
799
800
    component->io_callback = NULL;
    component->io_user_data = NULL;
801
802
    component->recv_messages = recv_messages;
    component->n_recv_messages = n_recv_messages;
803

804
    nice_component_deschedule_io_callback (component);
805
  }
806

807
  nice_input_message_iter_reset (&component->recv_messages_iter);
808
809
  component->recv_buf_error = error;

810
811
812
813
  g_mutex_unlock (&component->io_mutex);
}

gboolean
814
nice_component_has_io_callback (NiceComponent *component)
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
{
  gboolean has_io_callback;

  g_mutex_lock (&component->io_mutex);
  has_io_callback = (component->io_callback != NULL);
  g_mutex_unlock (&component->io_mutex);

  return has_io_callback;
}

IOCallbackData *
io_callback_data_new (const guint8 *buf, gsize buf_len)
{
  IOCallbackData *data;

  data = g_slice_new0 (IOCallbackData);
  data->buf = g_memdup (buf, buf_len);
  data->buf_len = buf_len;
  data->offset = 0;

  return data;
}

void
io_callback_data_free (IOCallbackData *data)
{
  g_free (data->buf);
  g_slice_free (IOCallbackData, data);
}

/* This is called with the global agent lock released. It does not take that
 * lock, but does take the io_mutex. */
static gboolean
emit_io_callback_cb (gpointer user_data)
{
850
  NiceComponent *component = user_data;
851
852
853
854
855
856
  IOCallbackData *data;
  NiceAgentRecvFunc io_callback;
  gpointer io_user_data;
  guint stream_id, component_id;
  NiceAgent *agent;

857
858
859
860
861
  agent = g_weak_ref_get (&component->agent_ref);
  if (agent == NULL) {
    nice_debug ("Agent for component %p is gone", component);
    return FALSE;
  }
862

863
  stream_id = component->stream_id;
864
865
866
867
868
  component_id = component->id;

  g_mutex_lock (&component->io_mutex);

  /* The members of Component are guaranteed not to have changed since this
869
   * GSource was attached in nice_component_emit_io_callback(). The Component’s agent
870
871
872
873
874
875
876
877
878
   * and stream are immutable after construction, as are the stream and
   * component IDs. The callback and its user data may have changed, but are
   * guaranteed to be non-%NULL at the start as the idle source is removed when
   * the callback is set to %NULL. They may become %NULL during the io_callback,
   * so must be re-checked every loop iteration. The data buffer is copied into
   * the #IOCallbackData closure.
   *
   * If the component is destroyed (which happens if the agent or stream are
   * destroyed) between attaching the GSource and firing it, the GSource is
879
   * detached during dispose and this callback is never invoked. If the
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
   * agent is destroyed during an io_callback, its weak pointer will be
   * nullified. Similarly, the Component needs to be re-queried for after every
   * iteration, just in case the client has removed the stream in the
   * callback. */
  while (TRUE) {
    io_callback = component->io_callback;
    io_user_data = component->io_user_data;
    data = g_queue_peek_head (&component->pending_io_messages);

    if (data == NULL || io_callback == NULL)
      break;

    g_mutex_unlock (&component->io_mutex);

    io_callback (agent, stream_id, component_id,
        data->buf_len - data->offset, (gchar *) data->buf + data->offset,
        io_user_data);

    /* Check for the user destroying things underneath our feet. */
899
    if (!agent_find_component (agent, stream_id, component_id,
900
901
            NULL, &component)) {
      nice_debug ("%s: Agent or component destroyed.", G_STRFUNC);
902
      goto done;
903
904
905
906
907
908
909
910
911
912
913
    }

    g_queue_pop_head (&component->pending_io_messages);
    io_callback_data_free (data);

    g_mutex_lock (&component->io_mutex);
  }

  component->io_callback_id = 0;
  g_mutex_unlock (&component->io_mutex);

914
915
 done:
  g_object_unref (agent);
916
917

  return G_SOURCE_REMOVE;
918
919
920
921
}

/* This must be called with the agent lock *held*. */
void
922
nice_component_emit_io_callback (NiceAgent *agent, NiceComponent *component,
923
    const guint8 *buf, gsize buf_len)
924
{
925
  guint stream_id, component_id;
926
927
928
929
930
931
932
  NiceAgentRecvFunc io_callback;
  gpointer io_user_data;

  g_assert (component != NULL);
  g_assert (buf != NULL);
  g_assert (buf_len > 0);

933
  stream_id = component->stream_id;
934
  component_id = component->id;
935
936

  g_mutex_lock (&component->io_mutex);
937
938
  io_callback = component->io_callback;
  io_user_data = component->io_user_data;
939
940
941
942
943
944
  g_mutex_unlock (&component->io_mutex);

  /* Allow this to be called with a NULL io_callback, since the caller can’t
   * lock io_mutex to check beforehand. */
  if (io_callback == NULL)
    return;
945

946
  g_assert (NICE_IS_AGENT (agent));
947
948
  g_assert_cmpuint (stream_id, >, 0);
  g_assert_cmpuint (component_id, >, 0);
949
950
  g_assert (io_callback != NULL);

951
952
953
954
  /* Only allocate a closure if the callback is being deferred to an idle
   * handler. */
  if (g_main_context_is_owner (component->ctx)) {
    /* Thread owns the main context, so invoke the callback directly. */
955
    agent_unlock_and_emit (agent);
956
957
    io_callback (agent, stream_id,
        component_id, buf_len, (gchar *) buf, io_user_data);
958
    agent_lock (agent);
959
960
961
962
963
964
965
966
967
968
969
970
971
  } else {
    IOCallbackData *data;

    g_mutex_lock (&component->io_mutex);

    /* Slow path: Current thread doesn’t own the Component’s context at the
     * moment, so schedule the callback in an idle handler. */
    data = io_callback_data_new (buf, buf_len);
    g_queue_push_tail (&component->pending_io_messages,
        data);  /* transfer ownership */

    nice_debug ("%s: **WARNING: SLOW PATH**", G_STRFUNC);

972
    nice_component_schedule_io_callback (component);
973
974
975
976
977
978
979

    g_mutex_unlock (&component->io_mutex);
  }
}

/* Note: Must be called with the io_mutex held. */
static void
980
nice_component_schedule_io_callback (NiceComponent *component)
981
982
{
  GSource *source;
983

984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
  /* Already scheduled or nothing to schedule? */
  if (component->io_callback_id != 0 ||
      g_queue_is_empty (&component->pending_io_messages))
    return;

  /* Add the idle callback. If nice_agent_attach_recv() is called with a
   * NULL callback before this source is dispatched, the source will be
   * destroyed, but any pending data will remain in
   * component->pending_io_messages, ready to be picked up when a callback
   * is re-attached, or if nice_agent_recv() is called. */
  source = g_idle_source_new ();
  g_source_set_priority (source, G_PRIORITY_DEFAULT);
  g_source_set_callback (source, emit_io_callback_cb, component, NULL);
  component->io_callback_id = g_source_attach (source, component->ctx);
  g_source_unref (source);
}

/* Note: Must be called with the io_mutex held. */
static void
1003
nice_component_deschedule_io_callback (NiceComponent *component)
1004
1005
1006
1007
{
  /* Already descheduled? */
  if (component->io_callback_id == 0)
    return;
1008

1009
1010
  g_source_remove (component->io_callback_id);
  component->io_callback_id = 0;
1011
}
1012

1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
static void
nice_component_class_init (NiceComponentClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->constructed = nice_component_constructed;
  object_class->get_property = nice_component_get_property;
  object_class->set_property = nice_component_set_property;
  object_class->finalize = nice_component_finalize;

  /**
   * NiceComponent:id:
   *
   * The unique numeric ID of the component.
   *
Olivier Crête's avatar
Olivier Crête committed
1028
   * Since: 0.1.14
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
   */
  g_object_class_install_property (object_class, PROP_ID,
      g_param_spec_uint (
         "id",
         "ID",
         "The unique numeric ID of the component.",
         1, G_MAXUINT, 1,
         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

  /**
   * NiceComponent:agent:
   *
   * The #NiceAgent this component belongs to.
   *
Olivier Crête's avatar
Olivier Crête committed
1043
   * Since: 0.1.14
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
   */
  g_object_class_install_property (object_class, PROP_AGENT,
      g_param_spec_object (
         "agent",
         "Agent",
         "The NiceAgent this component belongs to.",
         NICE_TYPE_AGENT,
         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

  /**
   * NiceComponent:stream:
   *
   * The #NiceStream this component belongs to.
   *
Olivier Crête's avatar
Olivier Crête committed
1058
   * Since: 0.1.14
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
   */
  g_object_class_install_property (object_class, PROP_STREAM,
      g_param_spec_object (
         "stream",
         "Stream",
         "The NiceStream this component belongs to.",
         NICE_TYPE_STREAM,
         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}

1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
static gboolean
dummy_callback (gpointer data)
{
  return G_SOURCE_CONTINUE;
}

static void
source_set_dummy_callback (GSource *source)
{
  g_source_set_callback (source, dummy_callback, NULL, NULL);
}

1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
static void
nice_component_init (NiceComponent *component)
{
  g_atomic_int_inc (&n_components_created);
  nice_debug ("Created NiceComponent (%u created, %u destroyed)",
      n_components_created, n_components_destroyed);

  component->id = 0;
  component->state = NICE_COMPONENT_STATE_DISCONNECTED;
  component->restart_candidate = NULL;
  component->tcp = NULL;
1092
  g_weak_ref_init (&component->agent_ref, NULL);
1093
1094
1095
1096
1097
1098
1099
1100
1101

  g_mutex_init (&component->io_mutex);
  g_queue_init (&component->pending_io_messages);
  component->io_callback_id = 0;

  component->own_ctx = g_main_context_new ();
  component->stop_cancellable = g_cancellable_new ();
  component->stop_cancellable_source =
      g_cancellable_source_new (component->stop_cancellable);
1102
  source_set_dummy_callback (component->stop_cancellable_source);
1103
1104
1105
1106
1107
1108
  g_source_attach (component->stop_cancellable_source, component->own_ctx);
  component->ctx = g_main_context_ref (component->own_ctx);

  /* Start off with a fresh main context and all I/O paused. This
   * will be updated when nice_agent_attach_recv() or nice_agent_recv_messages()
   * are called. */
1109
1110
  nice_component_set_io_context (component, NULL);
  nice_component_set_io_callback (component, NULL, NULL, NULL, 0, NULL);
1111
1112

  g_queue_init (&component->queued_tcp_packets);
1113
  g_queue_init (&component->incoming_checks);
1114
1115
1116
1117
1118
1119
}

static void
nice_component_constructed (GObject *obj)
{
  NiceComponent *component;
1120
  NiceAgent *agent;
1121
1122
1123

  component = NICE_COMPONENT (obj);

1124
1125
1126
1127
1128
  agent = g_weak_ref_get (&component->agent_ref);
  g_assert (agent != NULL);
  nice_agent_init_stun_agent (agent, &component->stun_agent);

  g_object_unref (agent);
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147

  G_OBJECT_CLASS (nice_component_parent_class)->constructed (obj);
}

static void
nice_component_get_property (GObject *obj,
    guint property_id, GValue *value, GParamSpec *pspec)
{
  NiceComponent *component;

  component = NICE_COMPONENT (obj);

  switch ((NiceComponentProperty) property_id)
    {
    case PROP_ID:
      g_value_set_uint (value, component->id);
      break;

    case PROP_AGENT:
1148
1149
      {
        NiceAgent *agent;
1150

1151
1152
1153
1154
1155
        agent = g_weak_ref_get (&component->agent_ref);
        if (agent)
          g_value_take_object (value, agent);
        break;
      }
1156
    case PROP_STREAM:
1157
      {
1158
1159
1160
1161
1162
1163
1164
1165
1166
        NiceAgent *agent;
        NiceStream *stream = NULL;

        agent = g_weak_ref_get (&component->agent_ref);
        if (agent) {
          stream = agent_find_stream (agent, component->stream_id);
          g_value_set_object (value, stream);
          g_object_unref (agent);
        }
1167
1168
        break;
      }
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
    }
}

static void
nice_component_set_property (GObject *obj,
    guint property_id, const GValue *value, GParamSpec *pspec)
{
  NiceComponent *component;

  component = NICE_COMPONENT (obj);

  switch ((NiceComponentProperty) property_id)
    {
    case PROP_ID:
      component->id = g_value_get_uint (value);
      break;

    case PROP_AGENT:
1189
      g_weak_ref_set (&component->agent_ref, g_value_get_object (value));
1190
1191
1192
      break;

    case PROP_STREAM:
1193
1194
1195
1196
      {
        NiceStream *stream = g_value_get_object (value);
        component->stream_id = stream->id;
      }
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
    }
}

/* Must be called with the agent lock released as it could dispose of
 * NiceIOStreams. */
static void
nice_component_finalize (GObject *obj)
{
  NiceComponent *cmp;

  cmp = NICE_COMPONENT (obj);

  /* Component should have been closed already. */
  g_warn_if_fail (cmp->local_candidates == NULL);
  g_warn_if_fail (cmp->remote_candidates == NULL);
1216
  g_warn_if_fail (g_queue_get_length (&cmp->incoming_checks) == 0);
1217

1218
1219
1220
  g_list_free_full (cmp->valid_candidates,
      (GDestroyNotify) nice_candidate_free);

1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
  g_clear_object (&cmp->tcp);
  g_clear_object (&cmp->stop_cancellable);
  g_clear_object (&cmp->iostream);
  g_mutex_clear (&cmp->io_mutex);

  if (cmp->stop_cancellable_source != NULL) {
    g_source_destroy (cmp->stop_cancellable_source);
    g_source_unref (cmp->stop_cancellable_source);
  }