agent.c 114 KB
Newer Older
1
2
3
/*
 * This file is part of the Nice GLib ICE library.
 *
4
 * (C) 2006-2010, 2013 Collabora Ltd.
5
6
 *  Contact: Youness Alaoui
 * (C) 2006-2010 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
 *   Philip Withnall, Collabora Ltd.
29
30
31
32
33
34
35
36
37
38
39
 *
 * 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.
 */
Dafydd Harries's avatar
Dafydd Harries committed
40

41
42
43

#ifdef HAVE_CONFIG_H
# include <config.h>
44
45
#else
#define NICEAPI_EXPORT
46
47
#endif

48
49
#include <glib.h>

Dafydd Harries's avatar
Dafydd Harries committed
50
#include <string.h>
51
#include <errno.h>
Dafydd Harries's avatar
Dafydd Harries committed
52

53
#ifndef G_OS_WIN32
54
55
56
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
57
#endif
Dafydd Harries's avatar
Dafydd Harries committed
58

59
60
#include "debug.h"

61
#include "socket.h"
62
#include "stun/usages/turn.h"
63
#include "candidate.h"
64
#include "component.h"
65
66
#include "conncheck.h"
#include "discovery.h"
67
#include "agent.h"
68
#include "agent-priv.h"
69
#include "agent-signals-marshal.h"
Dafydd Harries's avatar
Dafydd Harries committed
70

71
#include "stream.h"
72
#include "interfaces.h"
Dafydd Harries's avatar
Dafydd Harries committed
73

74
75
#include "pseudotcp.h"

76
77
78
79
/* This is the max size of a UDP packet
 * will it work tcp relaying??
 */
#define MAX_BUFFER_SIZE 65536
80
#define DEFAULT_STUN_PORT  3478
81
#define DEFAULT_UPNP_TIMEOUT 200
82

83
84
#define MAX_TCP_MTU 1400 /* Use 1400 because of VPNs and we assume IEE 802.3 */

Dafydd Harries's avatar
Dafydd Harries committed
85
86
87
88
G_DEFINE_TYPE (NiceAgent, nice_agent, G_TYPE_OBJECT);

enum
{
89
  PROP_COMPATIBILITY = 1,
90
  PROP_MAIN_CONTEXT,
91
  PROP_STUN_SERVER,
92
  PROP_STUN_SERVER_PORT,
93
  PROP_CONTROLLING_MODE,
94
  PROP_FULL_MODE,
95
  PROP_STUN_PACING_TIMER,
96
97
98
99
100
  PROP_MAX_CONNECTIVITY_CHECKS,
  PROP_PROXY_TYPE,
  PROP_PROXY_IP,
  PROP_PROXY_PORT,
  PROP_PROXY_USERNAME,
Youness Alaoui's avatar
Youness Alaoui committed
101
102
  PROP_PROXY_PASSWORD,
  PROP_UPNP,
103
104
  PROP_UPNP_TIMEOUT,
  PROP_RELIABLE
Dafydd Harries's avatar
Dafydd Harries committed
105
106
107
};


108
109
110
enum
{
  SIGNAL_COMPONENT_STATE_CHANGED,
111
  SIGNAL_CANDIDATE_GATHERING_DONE,
112
113
  SIGNAL_NEW_SELECTED_PAIR,
  SIGNAL_NEW_CANDIDATE,
114
  SIGNAL_NEW_REMOTE_CANDIDATE,
115
  SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED,
116
  SIGNAL_RELIABLE_TRANSPORT_WRITABLE,
117
  SIGNAL_STREAMS_REMOVED,
118
119
120
121
122
  N_SIGNALS,
};

static guint signals[N_SIGNALS];

123
124
125
126
127
#if GLIB_CHECK_VERSION(2,31,8)
static GRecMutex agent_mutex;    /* Mutex used for thread-safe lib */
#else
static GStaticRecMutex agent_mutex = G_STATIC_REC_MUTEX_INIT;
#endif
128

Youness Alaoui's avatar
Youness Alaoui committed
129
130
static void priv_free_upnp (NiceAgent *agent);

131
#if GLIB_CHECK_VERSION(2,31,8)
132
133
void agent_lock (void)
{
134
  g_rec_mutex_lock (&agent_mutex);
135
136
137
138
}

void agent_unlock (void)
{
139
140
141
142
143
144
145
  g_rec_mutex_unlock (&agent_mutex);
}

#else
void agent_lock(void)
{
  g_static_rec_mutex_lock (&agent_mutex);
146
147
}

148
149
150
151
void agent_unlock(void)
{
  g_static_rec_mutex_unlock (&agent_mutex);
}
152

153
#endif
154

155
156
157
StunUsageIceCompatibility
agent_to_ice_compatibility (NiceAgent *agent)
{
158
  return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
159
160
      STUN_USAGE_ICE_COMPATIBILITY_GOOGLE :
      agent->compatibility == NICE_COMPATIBILITY_MSN ?
161
      STUN_USAGE_ICE_COMPATIBILITY_MSN :
Jakub Adam's avatar
Jakub Adam committed
162
163
      agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
      STUN_USAGE_ICE_COMPATIBILITY_WLM2009 :
Jakub Adam's avatar
Jakub Adam committed
164
165
      agent->compatibility == NICE_COMPATIBILITY_OC2007 ?
      STUN_USAGE_ICE_COMPATIBILITY_MSN :
Jakub Adam's avatar
Jakub Adam committed
166
167
      agent->compatibility == NICE_COMPATIBILITY_OC2007R2 ?
      STUN_USAGE_ICE_COMPATIBILITY_WLM2009 :
168
      STUN_USAGE_ICE_COMPATIBILITY_RFC5245;
169
170
171
172
173
174
}


StunUsageTurnCompatibility
agent_to_turn_compatibility (NiceAgent *agent)
{
175
  return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
176
177
      STUN_USAGE_TURN_COMPATIBILITY_GOOGLE :
      agent->compatibility == NICE_COMPATIBILITY_MSN ?
178
179
      STUN_USAGE_TURN_COMPATIBILITY_MSN :
      agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
Jakub Adam's avatar
Jakub Adam committed
180
181
      STUN_USAGE_TURN_COMPATIBILITY_MSN :
      agent->compatibility == NICE_COMPATIBILITY_OC2007 ?
182
183
184
      STUN_USAGE_TURN_COMPATIBILITY_OC2007 :
      agent->compatibility == NICE_COMPATIBILITY_OC2007R2 ?
      STUN_USAGE_TURN_COMPATIBILITY_OC2007 :
Marcus Lundblad's avatar
Marcus Lundblad committed
185
      STUN_USAGE_TURN_COMPATIBILITY_RFC5766;
186
187
}

188
189
190
NiceTurnSocketCompatibility
agent_to_turn_socket_compatibility (NiceAgent *agent)
{
191
  return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
192
193
194
      NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE :
      agent->compatibility == NICE_COMPATIBILITY_MSN ?
      NICE_TURN_SOCKET_COMPATIBILITY_MSN :
195
196
      agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
      NICE_TURN_SOCKET_COMPATIBILITY_MSN :
Jakub Adam's avatar
Jakub Adam committed
197
      agent->compatibility == NICE_COMPATIBILITY_OC2007 ?
198
199
200
      NICE_TURN_SOCKET_COMPATIBILITY_OC2007 :
      agent->compatibility == NICE_COMPATIBILITY_OC2007R2 ?
      NICE_TURN_SOCKET_COMPATIBILITY_OC2007 :
Marcus Lundblad's avatar
Marcus Lundblad committed
201
      NICE_TURN_SOCKET_COMPATIBILITY_RFC5766;
202
203
}

204
Stream *agent_find_stream (NiceAgent *agent, guint stream_id)
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
{
  GSList *i;

  for (i = agent->streams; i; i = i->next)
    {
      Stream *s = i->data;

      if (s->id == stream_id)
        return s;
    }

  return NULL;
}


220
221
gboolean
agent_find_component (
222
223
224
225
226
227
228
  NiceAgent *agent,
  guint stream_id,
  guint component_id,
  Stream **stream,
  Component **component)
{
  Stream *s;
229
  Component *c;
230

231
  s = agent_find_stream (agent, stream_id);
232

233
  if (s == NULL)
234
235
    return FALSE;

236
237
238
239
240
  c = stream_find_component_by_id (s, component_id);

  if (c == NULL)
    return FALSE;

241
242
243
244
  if (stream)
    *stream = s;

  if (component)
245
    *component = c;
246
247
248
249
250

  return TRUE;
}


Dafydd Harries's avatar
Dafydd Harries committed
251
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
277
static void
nice_agent_dispose (GObject *object);

static void
nice_agent_get_property (
  GObject *object,
  guint property_id,
  GValue *value,
  GParamSpec *pspec);

static void
nice_agent_set_property (
  GObject *object,
  guint property_id,
  const GValue *value,
  GParamSpec *pspec);


static void
nice_agent_class_init (NiceAgentClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->get_property = nice_agent_get_property;
  gobject_class->set_property = nice_agent_set_property;
  gobject_class->dispose = nice_agent_dispose;

278
  /* install properties */
279
280
281
282
283
284
  /**
   * NiceAgent:main-context:
   *
   * A GLib main context is needed for all timeouts used by libnice.
   * This is a property being set by the nice_agent_new() call.
   */
285
286
287
288
289
290
291
  g_object_class_install_property (gobject_class, PROP_MAIN_CONTEXT,
      g_param_spec_pointer (
         "main-context",
         "The GMainContext to use for timeouts",
         "The GMainContext to use for timeouts",
         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

292
293
294
295
296
297
298
  /**
   * NiceAgent:compatibility:
   *
   * The Nice agent can work in various compatibility modes depending on
   * what the application/peer needs.
   * <para> See also: #NiceCompatibility</para>
   */
299
300
301
302
303
  g_object_class_install_property (gobject_class, PROP_COMPATIBILITY,
      g_param_spec_uint (
         "compatibility",
         "ICE specification compatibility",
         "The compatibility mode for the agent",
304
305
         NICE_COMPATIBILITY_RFC5245, NICE_COMPATIBILITY_LAST,
         NICE_COMPATIBILITY_RFC5245,
306
307
         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

Dafydd Harries's avatar
Dafydd Harries committed
308
  g_object_class_install_property (gobject_class, PROP_STUN_SERVER,
309
      g_param_spec_string (
Dafydd Harries's avatar
Dafydd Harries committed
310
        "stun-server",
311
312
        "STUN server IP address",
        "The IP address (not the hostname) of the STUN server to use",
313
        NULL,
Dafydd Harries's avatar
Dafydd Harries committed
314
315
        G_PARAM_READWRITE));

316
317
318
319
  g_object_class_install_property (gobject_class, PROP_STUN_SERVER_PORT,
      g_param_spec_uint (
        "stun-server-port",
        "STUN server port",
320
        "Port of the STUN server used to gather server-reflexive candidates",
Youness Alaoui's avatar
Youness Alaoui committed
321
        1, 65536,
322
	1, /* not a construct property, ignored */
323
324
        G_PARAM_READWRITE));

325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
  g_object_class_install_property (gobject_class, PROP_CONTROLLING_MODE,
      g_param_spec_boolean (
        "controlling-mode",
        "ICE controlling mode",
        "Whether the agent is in controlling mode",
	FALSE, /* not a construct property, ignored */
        G_PARAM_READWRITE));

   g_object_class_install_property (gobject_class, PROP_FULL_MODE,
      g_param_spec_boolean (
        "full-mode",
        "ICE full mode",
        "Whether agent runs in ICE full mode",
	TRUE, /* use full mode by default */
        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

341
342
343
344
  g_object_class_install_property (gobject_class, PROP_STUN_PACING_TIMER,
      g_param_spec_uint (
        "stun-pacing-timer",
        "STUN pacing timer",
Youness Alaoui's avatar
Youness Alaoui committed
345
346
        "Timer 'Ta' (msecs) used in the IETF ICE specification for pacing "
        "candidate gathering and sending of connectivity checks",
Youness Alaoui's avatar
Youness Alaoui committed
347
        1, 0xffffffff,
348
349
350
	NICE_AGENT_TIMER_TA_DEFAULT,
        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

351
  /* note: according to spec recommendation in sect 5.7.3 (ID-19) */
352
353
354
355
356
  g_object_class_install_property (gobject_class, PROP_MAX_CONNECTIVITY_CHECKS,
      g_param_spec_uint (
        "max-connectivity-checks",
        "Maximum number of connectivity checks",
        "Upper limit for the total number of connectivity checks performed",
Youness Alaoui's avatar
Youness Alaoui committed
357
        0, 0xffffffff,
358
359
360
	0, /* default set in init */
        G_PARAM_READWRITE));

361
362
363
364
365
366
367
  /**
   * NiceAgent:proxy-ip:
   *
   * The proxy server IP used to bypass a proxy firewall
   *
   * Since: 0.0.4
   */
368
369
370
371
  g_object_class_install_property (gobject_class, PROP_PROXY_IP,
      g_param_spec_string (
        "proxy-ip",
        "Proxy server IP",
372
        "The proxy server IP used to bypass a proxy firewall",
373
374
375
        NULL,
        G_PARAM_READWRITE));

376
377
378
379
380
381
382
  /**
   * NiceAgent:proxy-port:
   *
   * The proxy server port used to bypass a proxy firewall
   *
   * Since: 0.0.4
   */
383
384
385
386
  g_object_class_install_property (gobject_class, PROP_PROXY_PORT,
      g_param_spec_uint (
        "proxy-port",
        "Proxy server port",
387
        "The Proxy server port used to bypass a proxy firewall",
388
389
390
391
        1, 65536,
	1,
        G_PARAM_READWRITE));

392
393
394
395
396
397
398
  /**
   * NiceAgent:proxy-type:
   *
   * The type of proxy set in the proxy-ip property
   *
   * Since: 0.0.4
   */
399
400
401
402
403
404
405
406
407
  g_object_class_install_property (gobject_class, PROP_PROXY_TYPE,
      g_param_spec_uint (
         "proxy-type",
         "Type of proxy to use",
         "The type of proxy set in the proxy-ip property",
         NICE_PROXY_TYPE_NONE, NICE_PROXY_TYPE_LAST,
         NICE_PROXY_TYPE_NONE,
         G_PARAM_READWRITE));

408
409
410
411
412
413
414
  /**
   * NiceAgent:proxy-username:
   *
   * The username used to authenticate with the proxy
   *
   * Since: 0.0.4
   */
415
416
417
418
419
420
421
422
  g_object_class_install_property (gobject_class, PROP_PROXY_USERNAME,
      g_param_spec_string (
        "proxy-username",
        "Proxy server username",
        "The username used to authenticate with the proxy",
        NULL,
        G_PARAM_READWRITE));

423
424
425
426
427
428
429
  /**
   * NiceAgent:proxy-password:
   *
   * The password used to authenticate with the proxy
   *
   * Since: 0.0.4
   */
430
431
432
433
434
435
436
437
  g_object_class_install_property (gobject_class, PROP_PROXY_PASSWORD,
      g_param_spec_string (
        "proxy-password",
        "Proxy server password",
        "The password used to authenticate with the proxy",
        NULL,
        G_PARAM_READWRITE));

438
439
440
441
442
443
444
445
  /**
   * NiceAgent:upnp:
   *
   * Whether the agent should use UPnP to open a port in the router and
   * get the external IP
   *
   * Since: 0.0.7
   */
Youness Alaoui's avatar
Youness Alaoui committed
446
447
448
   g_object_class_install_property (gobject_class, PROP_UPNP,
      g_param_spec_boolean (
        "upnp",
449
#ifdef HAVE_GUPNP
Youness Alaoui's avatar
Youness Alaoui committed
450
451
452
        "Use UPnP",
        "Whether the agent should use UPnP to open a port in the router and "
        "get the external IP",
453
454
455
456
#else
        "Use UPnP (disabled in build)",
        "Does nothing because libnice was not built with UPnP support",
#endif
Youness Alaoui's avatar
Youness Alaoui committed
457
458
459
	TRUE, /* enable UPnP by default */
        G_PARAM_READWRITE| G_PARAM_CONSTRUCT));

460
461
462
463
  /**
   * NiceAgent:upnp-timeout:
   *
   * The maximum amount of time to wait for UPnP discovery to finish before
464
   * signaling the #NiceAgent::candidate-gathering-done signal
465
466
467
   *
   * Since: 0.0.7
   */
Youness Alaoui's avatar
Youness Alaoui committed
468
469
470
  g_object_class_install_property (gobject_class, PROP_UPNP_TIMEOUT,
      g_param_spec_uint (
        "upnp-timeout",
471
#ifdef HAVE_GUPNP
Youness Alaoui's avatar
Youness Alaoui committed
472
473
474
        "Timeout for UPnP discovery",
        "The maximum amount of time to wait for UPnP discovery to finish before "
        "signaling the candidate-gathering-done signal",
475
476
477
478
#else
        "Timeout for UPnP discovery (disabled in build)",
        "Does nothing because libnice was not built with UPnP support",
#endif
Youness Alaoui's avatar
Youness Alaoui committed
479
        100, 60000,
480
	DEFAULT_UPNP_TIMEOUT,
Youness Alaoui's avatar
Youness Alaoui committed
481
482
        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));

Youness Alaoui's avatar
Youness Alaoui committed
483
484
485
486
487
488
489
490
  /**
   * NiceAgent:reliable:
   *
   * Whether the agent should use PseudoTcp to ensure a reliable transport
   * of messages
   *
   * Since: 0.0.11
   */
491
492
493
494
   g_object_class_install_property (gobject_class, PROP_RELIABLE,
      g_param_spec_boolean (
        "reliable",
        "reliable mode",
Youness Alaoui's avatar
Youness Alaoui committed
495
        "Whether the agent should use PseudoTcp to ensure a reliable transport"
496
497
498
499
        "of messages",
	FALSE,
        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

500
501
  /* install signals */

502
503
  /**
   * NiceAgent::component-state-changed
Youness Alaoui's avatar
Youness Alaoui committed
504
   * @agent: The #NiceAgent object
505
506
507
508
509
510
   * @stream_id: The ID of the stream
   * @component_id: The ID of the component
   * @state: The #NiceComponentState of the component
   *
   * This signal is fired whenever a component's state changes
   */
511
512
513
514
  signals[SIGNAL_COMPONENT_STATE_CHANGED] =
      g_signal_new (
          "component-state-changed",
          G_OBJECT_CLASS_TYPE (klass),
515
          G_SIGNAL_RUN_LAST,
516
517
518
519
520
521
522
523
          0,
          NULL,
          NULL,
          agent_marshal_VOID__UINT_UINT_UINT,
          G_TYPE_NONE,
          3,
          G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
          G_TYPE_INVALID);
524

525
526
  /**
   * NiceAgent::candidate-gathering-done:
Youness Alaoui's avatar
Youness Alaoui committed
527
   * @agent: The #NiceAgent object
528
529
530
531
532
   * @stream_id: The ID of the stream
   *
   * This signal is fired whenever a stream has finished gathering its
   * candidates after a call to nice_agent_gather_candidates()
   */
533
534
535
536
  signals[SIGNAL_CANDIDATE_GATHERING_DONE] =
      g_signal_new (
          "candidate-gathering-done",
          G_OBJECT_CLASS_TYPE (klass),
537
          G_SIGNAL_RUN_LAST,
538
539
540
          0,
          NULL,
          NULL,
541
          agent_marshal_VOID__UINT,
542
          G_TYPE_NONE,
543
544
          1,
          G_TYPE_UINT, G_TYPE_INVALID);
545

546
547
  /**
   * NiceAgent::new-selected-pair
Youness Alaoui's avatar
Youness Alaoui committed
548
   * @agent: The #NiceAgent object
549
550
551
552
553
554
555
556
   * @stream_id: The ID of the stream
   * @component_id: The ID of the component
   * @lfoundation: The local foundation of the selected candidate pair
   * @rfoundation: The remote foundation of the selected candidate pair
   *
   * This signal is fired once a candidate pair is selected for data transfer for
   * a stream's component
   */
557
558
559
560
  signals[SIGNAL_NEW_SELECTED_PAIR] =
      g_signal_new (
          "new-selected-pair",
          G_OBJECT_CLASS_TYPE (klass),
561
          G_SIGNAL_RUN_LAST,
562
563
564
565
566
567
568
569
570
          0,
          NULL,
          NULL,
          agent_marshal_VOID__UINT_UINT_STRING_STRING,
          G_TYPE_NONE,
          4,
          G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING,
          G_TYPE_INVALID);

571
572
  /**
   * NiceAgent::new-candidate
Youness Alaoui's avatar
Youness Alaoui committed
573
   * @agent: The #NiceAgent object
574
575
576
577
578
   * @stream_id: The ID of the stream
   * @component_id: The ID of the component
   * @foundation: The foundation of the new candidate
   *
   * This signal is fired when the agent discovers a new candidate
579
   * <para> See also: #NiceAgent::candidate-gathering-done </para>
580
   */
581
582
583
584
  signals[SIGNAL_NEW_CANDIDATE] =
      g_signal_new (
          "new-candidate",
          G_OBJECT_CLASS_TYPE (klass),
585
          G_SIGNAL_RUN_LAST,
586
587
588
589
590
591
592
593
594
          0,
          NULL,
          NULL,
          agent_marshal_VOID__UINT_UINT_STRING,
          G_TYPE_NONE,
          3,
          G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
          G_TYPE_INVALID);

595
596
  /**
   * NiceAgent::new-remote-candidate
Youness Alaoui's avatar
Youness Alaoui committed
597
   * @agent: The #NiceAgent object
598
599
600
601
602
603
604
   * @stream_id: The ID of the stream
   * @component_id: The ID of the component
   * @foundation: The foundation of the new candidate
   *
   * This signal is fired when the agent discovers a new remote candidate.
   * This can happen with peer reflexive candidates.
   */
605
606
607
608
  signals[SIGNAL_NEW_REMOTE_CANDIDATE] =
      g_signal_new (
          "new-remote-candidate",
          G_OBJECT_CLASS_TYPE (klass),
609
          G_SIGNAL_RUN_LAST,
610
611
612
613
614
615
616
617
618
          0,
          NULL,
          NULL,
          agent_marshal_VOID__UINT_UINT_STRING,
          G_TYPE_NONE,
          3,
          G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
          G_TYPE_INVALID);

619
620
  /**
   * NiceAgent::initial-binding-request-received
Youness Alaoui's avatar
Youness Alaoui committed
621
   * @agent: The #NiceAgent object
622
623
624
625
626
   * @stream_id: The ID of the stream
   *
   * This signal is fired when we received our first binding request from
   * the peer.
   */
627
628
629
630
  signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED] =
      g_signal_new (
          "initial-binding-request-received",
          G_OBJECT_CLASS_TYPE (klass),
631
          G_SIGNAL_RUN_LAST,
632
633
634
635
636
637
638
639
640
          0,
          NULL,
          NULL,
          agent_marshal_VOID__UINT,
          G_TYPE_NONE,
          1,
          G_TYPE_UINT,
          G_TYPE_INVALID);

641
642
  /**
   * NiceAgent::reliable-transport-writable
Youness Alaoui's avatar
Youness Alaoui committed
643
   * @agent: The #NiceAgent object
644
645
646
647
648
649
650
651
   * @stream_id: The ID of the stream
   * @component_id: The ID of the component
   *
   * This signal is fired on the reliable #NiceAgent when the underlying reliable
   * transport becomes writable.
   * This signal is only emitted when the nice_agent_send() function returns less
   * bytes than requested to send (or -1) and once when the connection
   * is established.
652
653
   *
   * Since: 0.0.11
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
   */
  signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE] =
      g_signal_new (
          "reliable-transport-writable",
          G_OBJECT_CLASS_TYPE (klass),
          G_SIGNAL_RUN_LAST,
          0,
          NULL,
          NULL,
          agent_marshal_VOID__UINT_UINT,
          G_TYPE_NONE,
          2,
          G_TYPE_UINT, G_TYPE_UINT,
          G_TYPE_INVALID);

669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
  /**
   * NiceAgent::streams-removed
   * @agent: The #NiceAgent object
   * @stream_ids: (array zero-terminated=1) (element-type uint): An array of
   * unsigned integer stream IDs, ending with a 0 ID
   *
   * This signal is fired whenever one or more streams are removed from the
   * @agent.
   *
   * Since: 0.1.5
   */
  signals[SIGNAL_STREAMS_REMOVED] =
      g_signal_new (
          "streams-removed",
          G_OBJECT_CLASS_TYPE (klass),
          G_SIGNAL_RUN_LAST,
          0,
          NULL,
          NULL,
          g_cclosure_marshal_VOID__POINTER,
          G_TYPE_NONE,
          1,
          G_TYPE_POINTER,
          G_TYPE_INVALID);
693

694
695
  /* Init debug options depending on env variables */
  nice_debug_init ();
Dafydd Harries's avatar
Dafydd Harries committed
696
697
}

698
699
700
701
static void priv_generate_tie_breaker (NiceAgent *agent) 
{
  nice_rng_generate_bytes (agent->rng, 8, (gchar*)&agent->tie_breaker);
}
Dafydd Harries's avatar
Dafydd Harries committed
702
703
704
705
706
707

static void
nice_agent_init (NiceAgent *agent)
{
  agent->next_candidate_id = 1;
  agent->next_stream_id = 1;
708

709
  /* set defaults; not construct params, so set here */
710
  agent->stun_server_port = DEFAULT_STUN_PORT;
711
  agent->controlling_mode = TRUE;
712
  agent->max_conn_checks = NICE_AGENT_MAX_CONNECTIVITY_CHECKS_DEFAULT;
713
714

  agent->discovery_list = NULL;
715
  agent->discovery_unsched_items = 0;
716
717
718
  agent->discovery_timer_source = NULL;
  agent->conncheck_timer_source = NULL;
  agent->keepalive_timer_source = NULL;
719
  agent->refresh_list = NULL;
720
  agent->media_after_tick = FALSE;
721
  agent->software_attribute = NULL;
722

723
  agent->compatibility = NICE_COMPATIBILITY_RFC5245;
724
  agent->reliable = FALSE;
725

726
  stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
727
      STUN_COMPATIBILITY_RFC5389,
728
729
730
      STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
      STUN_AGENT_USAGE_USE_FINGERPRINT);

Dafydd Harries's avatar
Dafydd Harries committed
731
  agent->rng = nice_rng_new ();
732
  priv_generate_tie_breaker (agent);
Dafydd Harries's avatar
Dafydd Harries committed
733
734
735
}


736
NICEAPI_EXPORT NiceAgent *
737
nice_agent_new (GMainContext *ctx, NiceCompatibility compat)
Dafydd Harries's avatar
Dafydd Harries committed
738
{
739
740
  NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
      "compatibility", compat,
741
      "main-context", ctx,
742
743
744
745
746
747
748
749
750
751
752
753
754
755
      "reliable", FALSE,
      NULL);

  return agent;
}


NICEAPI_EXPORT NiceAgent *
nice_agent_new_reliable (GMainContext *ctx, NiceCompatibility compat)
{
  NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
      "compatibility", compat,
      "main-context", ctx,
      "reliable", TRUE,
Dafydd Harries's avatar
Dafydd Harries committed
756
      NULL);
757
758

  return agent;
Dafydd Harries's avatar
Dafydd Harries committed
759
760
761
762
763
764
765
766
767
768
769
}


static void
nice_agent_get_property (
  GObject *object,
  guint property_id,
  GValue *value,
  GParamSpec *pspec)
{
  NiceAgent *agent = NICE_AGENT (object);
Dafydd Harries's avatar
Dafydd Harries committed
770

771
  agent_lock();
Youness Alaoui's avatar
Youness Alaoui committed
772

Dafydd Harries's avatar
Dafydd Harries committed
773
774
  switch (property_id)
    {
775
776
777
778
    case PROP_MAIN_CONTEXT:
      g_value_set_pointer (value, agent->main_context);
      break;

779
780
781
782
    case PROP_COMPATIBILITY:
      g_value_set_uint (value, agent->compatibility);
      break;

Dafydd Harries's avatar
Dafydd Harries committed
783
    case PROP_STUN_SERVER:
784
      g_value_set_string (value, agent->stun_server_ip);
785
      break;
786
787
788

    case PROP_STUN_SERVER_PORT:
      g_value_set_uint (value, agent->stun_server_port);
789
      break;
790

791
792
793
794
795
796
797
    case PROP_CONTROLLING_MODE:
      g_value_set_boolean (value, agent->controlling_mode);
      break;

    case PROP_FULL_MODE:
      g_value_set_boolean (value, agent->full_mode);
      break;
Dafydd Harries's avatar
Dafydd Harries committed
798

799
800
801
802
    case PROP_STUN_PACING_TIMER:
      g_value_set_uint (value, agent->timer_ta);
      break;

803
804
805
806
807
    case PROP_MAX_CONNECTIVITY_CHECKS:
      g_value_set_uint (value, agent->max_conn_checks);
      /* XXX: should we prune the list of already existing checks? */
      break;

808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
    case PROP_PROXY_IP:
      g_value_set_string (value, agent->proxy_ip);
      break;

    case PROP_PROXY_PORT:
      g_value_set_uint (value, agent->proxy_port);
      break;

    case PROP_PROXY_TYPE:
      g_value_set_uint (value, agent->proxy_type);
      break;

    case PROP_PROXY_USERNAME:
      g_value_set_string (value, agent->proxy_username);
      break;

    case PROP_PROXY_PASSWORD:
      g_value_set_string (value, agent->proxy_password);
      break;

Youness Alaoui's avatar
Youness Alaoui committed
828
    case PROP_UPNP:
829
#ifdef HAVE_GUPNP
Youness Alaoui's avatar
Youness Alaoui committed
830
      g_value_set_boolean (value, agent->upnp_enabled);
831
832
833
#else
      g_value_set_boolean (value, FALSE);
#endif
Youness Alaoui's avatar
Youness Alaoui committed
834
835
836
      break;

    case PROP_UPNP_TIMEOUT:
837
#ifdef HAVE_GUPNP
Youness Alaoui's avatar
Youness Alaoui committed
838
      g_value_set_uint (value, agent->upnp_timeout);
839
840
#else
      g_value_set_uint (value, DEFAULT_UPNP_TIMEOUT);
Youness Alaoui's avatar
Youness Alaoui committed
841
#endif
842
      break;
Youness Alaoui's avatar
Youness Alaoui committed
843

844
845
846
847
    case PROP_RELIABLE:
      g_value_set_boolean (value, agent->reliable);
      break;

Dafydd Harries's avatar
Dafydd Harries committed
848
849
850
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
Youness Alaoui's avatar
Youness Alaoui committed
851

852
  agent_unlock();
Dafydd Harries's avatar
Dafydd Harries committed
853
854
855
856
857
858
859
860
861
862
863
864
}


static void
nice_agent_set_property (
  GObject *object,
  guint property_id,
  const GValue *value,
  GParamSpec *pspec)
{
  NiceAgent *agent = NICE_AGENT (object);

865
  agent_lock();
Youness Alaoui's avatar
Youness Alaoui committed
866

Dafydd Harries's avatar
Dafydd Harries committed
867
868
  switch (property_id)
    {
869
870
    case PROP_MAIN_CONTEXT:
      agent->main_context = g_value_get_pointer (value);
871
872
      if (agent->main_context != NULL)
        g_main_context_ref (agent->main_context);
873
874
      break;

875
876
    case PROP_COMPATIBILITY:
      agent->compatibility = g_value_get_uint (value);
877
      if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
878
879
880
881
        stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
            STUN_COMPATIBILITY_RFC3489,
            STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
            STUN_AGENT_USAGE_IGNORE_CREDENTIALS);
882
      } else if (agent->compatibility == NICE_COMPATIBILITY_MSN) {
Youness Alaoui's avatar
Youness Alaoui committed
883
884
        stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
            STUN_COMPATIBILITY_RFC3489,
885
886
            STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
            STUN_AGENT_USAGE_FORCE_VALIDATER);
887
888
889
890
      } else if (agent->compatibility == NICE_COMPATIBILITY_WLM2009) {
        stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
            STUN_COMPATIBILITY_WLM2009,
            STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
Jakub Adam's avatar
Jakub Adam committed
891
            STUN_AGENT_USAGE_USE_FINGERPRINT);
892
893
894
895
896
897
      } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007) {
        stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
            STUN_COMPATIBILITY_RFC3489,
            STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
            STUN_AGENT_USAGE_FORCE_VALIDATER |
            STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES);
Jakub Adam's avatar
Jakub Adam committed
898
899
900
901
      } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
        stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
            STUN_COMPATIBILITY_WLM2009,
            STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
902
903
            STUN_AGENT_USAGE_USE_FINGERPRINT |
            STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES);
904
905
906
907
908
      } else {
        stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
            STUN_COMPATIBILITY_RFC5389,
            STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
            STUN_AGENT_USAGE_USE_FINGERPRINT);
909
      }
910
      stun_agent_set_software (&agent->stun_agent, agent->software_attribute);
911

912
913
      break;

Dafydd Harries's avatar
Dafydd Harries committed
914
    case PROP_STUN_SERVER:
915
      g_free (agent->stun_server_ip);
916
917
918
919
920
921
922
      agent->stun_server_ip = g_value_dup_string (value);
      break;

    case PROP_STUN_SERVER_PORT:
      agent->stun_server_port = g_value_get_uint (value);
      break;

923
924
925
926
927
928
929
930
    case PROP_CONTROLLING_MODE:
      agent->controlling_mode = g_value_get_boolean (value);
      break;

    case PROP_FULL_MODE:
      agent->full_mode = g_value_get_boolean (value);
      break;

931
932
933
934
    case PROP_STUN_PACING_TIMER:
      agent->timer_ta = g_value_get_uint (value);
      break;

935
936
937
938
    case PROP_MAX_CONNECTIVITY_CHECKS:
      agent->max_conn_checks = g_value_get_uint (value);
      break;

939
    case PROP_PROXY_IP:
940
      g_free (agent->proxy_ip);
941
942
943
944
945
946
947
948
949
950
951
952
      agent->proxy_ip = g_value_dup_string (value);
      break;

    case PROP_PROXY_PORT:
      agent->proxy_port = g_value_get_uint (value);
      break;

    case PROP_PROXY_TYPE:
      agent->proxy_type = g_value_get_uint (value);
      break;

    case PROP_PROXY_USERNAME:
953
      g_free (agent->proxy_username);
954
955
956
957
      agent->proxy_username = g_value_dup_string (value);
      break;

    case PROP_PROXY_PASSWORD:
958
      g_free (agent->proxy_password);
959
960
961
      agent->proxy_password = g_value_dup_string (value);
      break;

Youness Alaoui's avatar
Youness Alaoui committed
962
    case PROP_UPNP_TIMEOUT:
963
#ifdef HAVE_GUPNP
Youness Alaoui's avatar
Youness Alaoui committed
964
      agent->upnp_timeout = g_value_get_uint (value);
965
#endif
Youness Alaoui's avatar
Youness Alaoui committed
966
967
968
      break;

    case PROP_UPNP:
969
#ifdef HAVE_GUPNP
Youness Alaoui's avatar
Youness Alaoui committed
970
971
      agent->upnp_enabled = g_value_get_boolean (value);
#endif
972
      break;
973
974
975
976
977

    case PROP_RELIABLE:
      agent->reliable = g_value_get_boolean (value);
      break;

Dafydd Harries's avatar
Dafydd Harries committed
978
979
980
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
Youness Alaoui's avatar
Youness Alaoui committed
981

982
  agent_unlock();
Youness Alaoui's avatar
Youness Alaoui committed
983

Dafydd Harries's avatar
Dafydd Harries committed
984
985
}

986
987
988
989
990
991
static void priv_pseudo_tcp_error (NiceAgent *agent, Stream *stream,
    Component *component)
{
  if (component->tcp) {
    agent_signal_component_state_change (agent, stream->id,
        component->id, NICE_COMPONENT_STATE_FAILED);
992
    component_detach_all_sockets (component);
993
994
995
996
997
998
999
1000
1001
    pseudo_tcp_socket_close (component->tcp, TRUE);
    g_object_unref (component->tcp);
    component->tcp = NULL;
  }

  if (component->tcp_clock) {
    g_source_destroy (component->tcp_clock);
    g_source_unref (component->tcp_clock);
    component->tcp_clock = NULL;
1002
1003
1004
1005
1006
  }
}

static void
adjust_tcp_clock (NiceAgent *agent, Stream *stream, Component *component);
1007
1008
1009
1010
1011


static void
pseudo_tcp_socket_opened (PseudoTcpSocket *sock, gpointer user_data)
{
1012
1013
1014
  Component *component = user_data;
  NiceAgent *agent = component->agent;
  Stream *stream = component->stream;
1015

1016
  nice_debug ("Agent %p: s%d:%d pseudo Tcp socket Opened", agent,
1017
1018
1019
1020
1021
1022
1023
1024
      stream->id, component->id);
  g_signal_emit (agent, signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE], 0,
      stream->id, component->id);
}

static void
pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data)
{
1025
1026
1027
  Component *component = user_data;
  NiceAgent *agent = component->agent;
  Stream *stream = component->stream;
1028
1029
  guint8 buf[MAX_BUFFER_SIZE];
  gssize len;
1030
  gboolean has_io_callback;
1031
1032
1033
1034

  nice_debug ("Agent %p: s%d:%d pseudo Tcp socket readable", agent,
      stream->id, component->id);

1035
1036
  component->tcp_readable = TRUE;

1037
1038
  g_object_add_weak_pointer (G_OBJECT (sock), (gpointer *)&sock);
  g_object_add_weak_pointer (G_OBJECT (agent), (gpointer *)&agent);
1039
  has_io_callback = component_has_io_callback (component);
1040

1041
  do {
1042
1043
    /* Only dequeue pseudo-TCP data if we can reliably inform the client. */
    if (has_io_callback) {
1044
      len = pseudo_tcp_socket_recv (sock, (gchar *) buf, sizeof(buf));
1045
1046
1047
1048
1049
    } else if (component->recv_buf != NULL) {
      len = pseudo_tcp_socket_recv (sock,
          (gchar *) component->recv_buf + component->recv_buf_valid_len,
          component->recv_buf_len - component->recv_buf_valid_len);
    } else {
1050
      len = 0;
1051
    }
1052

1053
1054
1055
    nice_debug ("%s: len %" G_GSSIZE_FORMAT, G_STRFUNC, len);

    if (len > 0 && has_io_callback) {
1056
      component_emit_io_callback (component, buf, len);
1057
1058
1059
1060
      if (sock == NULL) {
        nice_debug ("PseudoTCP socket got destroyed in readable callback!");
        break;
      }
1061
1062
1063
1064
    } else if (len > 0 && component->recv_buf != NULL) {
      /* No callback to call. The data has been copied directly into the
       * client’s receive buffer. */
      component->recv_buf_valid_len += len;
1065
1066
1067
    } else if (len < 0 &&
        pseudo_tcp_socket_get_error (sock) != EWOULDBLOCK) {
      /* Signal error */
1068
      nice_debug ("%s: calling priv_pseudo_tcp_error()", G_STRFUNC);
1069
      priv_pseudo_tcp_error (agent, stream, component);
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081

      if (component->recv_buf != NULL) {
        GIOErrorEnum error_code;

        if (pseudo_tcp_socket_get_error (sock) == ENOTCONN)
          error_code = G_IO_ERROR_BROKEN_PIPE;
        else
          error_code = G_IO_ERROR_FAILED;

        g_set_error (component->recv_buf_error, G_IO_ERROR, error_code,
            "Error reading data from pseudo-TCP socket.");
      }
1082
1083
1084
    } else if (len < 0 &&
        pseudo_tcp_socket_get_error (sock) == EWOULDBLOCK){
      component->tcp_readable = FALSE;
1085
    }
1086
1087
1088
1089
1090

    has_io_callback = component_has_io_callback (component);
  } while (len > 0 &&
           (has_io_callback ||
            component->recv_buf_valid_len < component->recv_buf_len));
1091

1092
  if (agent) {
1093
    adjust_tcp_clock (agent, stream, component);
1094
1095
    g_object_remove_weak_pointer (G_OBJECT (agent), (gpointer *)&agent);
  } else {
1096
    nice_debug ("Not calling adjust_tcp_clock.. agent got destroyed!");
1097
1098
1099
  }
  if (sock)
    g_object_remove_weak_pointer (G_OBJECT (sock), (gpointer *)&sock);
1100
1101
1102
1103
1104
}

static void
pseudo_tcp_socket_writable (PseudoTcpSocket *sock, gpointer user_data)
{
1105
1106
1107
  Component *component = user_data;
  NiceAgent *agent = component->agent;
  Stream *stream = component->stream;
1108

1109
1110
  nice_debug ("Agent %p: s%d:%d pseudo Tcp socket writable", agent,
      stream->id, component->id);
1111
1112
1113
1114
1115
1116
1117
1118
  g_signal_emit (agent, signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE], 0,
      stream->id, component->id);
}

static void
pseudo_tcp_socket_closed (PseudoTcpSocket *sock, guint32 err,
    gpointer user_data)
{
1119
1120
1121
  Component *component = user_data;
  NiceAgent *agent = component->agent;
  Stream *stream = component->stream;
1122

1123
1124
  nice_debug ("Agent %p: s%d:%d pseudo Tcp socket closed. "
      "Calling priv_pseudo_tcp_error().",  agent, stream->id, component->id);
1125
  priv_pseudo_tcp_error (agent, stream, component);
1126
1127
1128
1129
}


static PseudoTcpWriteResult
Philip Withnall's avatar
Philip Withnall committed
1130
pseudo_tcp_socket_write_packet (PseudoTcpSocket *socket,
1131
1132
    const gchar *buffer, guint32 len, gpointer user_data)
{
1133
  Component *component = user_data;
1134
1135
1136
1137
1138
1139
1140
1141
1142

  if (component->selected_pair.local != NULL) {
    NiceSocket *sock;
    NiceAddress *addr;

#ifndef NDEBUG
    gchar tmpbuf[INET6_ADDRSTRLEN];
    nice_address_to_string (&component->selected_pair.remote->addr, tmpbuf);

1143
1144
1145
1146
    nice_debug (
        "Agent %p : s%d:%d: sending %d bytes on socket %p (FD %d) to [%s]:%d",
        component->agent, component->stream->id, component->id, len,
        sock->fileno, g_socket_get_fd (sock->fileno), tmpbuf,
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
        nice_address_get_port (&component->selected_pair.remote->addr));
#endif

    sock = component->selected_pair.local->sockptr;
    addr = &component->selected_pair.remote->addr;
    if (nice_socket_send (sock, addr, len, buffer)) {
      return WR_SUCCESS;
    }
  }

  return WR_FAIL;
}


static gboolean
notify_pseudo_tcp_socket_clock (gpointer user_data)
{
1164
1165
1166
  Component *component = user_data;
  Stream *stream = component->stream;
  NiceAgent *agent = component->agent;
1167
1168
1169

  agent_lock();

1170
1171
1172
1173
1174
1175
  if (g_source_is_destroyed (g_main_current_source ())) {
    nice_debug ("Source was destroyed. "
        "Avoided race condition in notify_pseudo_tcp_socket_clock");
    agent_unlock ();
    return FALSE;
  }
1176
1177
1178
1179
1180
1181
1182
  if (component->tcp_clock) {
    g_source_destroy (component->tcp_clock);
    g_source_unref (component->tcp_clock);
    component->tcp_clock = NULL;
  }

  pseudo_tcp_socket_notify_clock (component->tcp);
1183
  adjust_tcp_clock (agent, stream, component);
1184
1185
1186
1187
1188
1189

  agent_unlock();

  return FALSE;
}

1190
1191
static void
adjust_tcp_clock (NiceAgent *agent, Stream *stream, Component *component)
1192
1193
{
  long timeout = 0;
1194
1195
1196
1197
1198
1199
1200
1201
  if (component->tcp) {
    if (pseudo_tcp_socket_get_next_clock (component->tcp, &timeout)) {
      if (component->tcp_clock) {
        g_source_destroy (component->tcp_clock);
        g_source_unref (component->tcp_clock);
        component->tcp_clock = NULL;
      }
      component->tcp_clock = agent_timeout_add_with_context (agent,
1202
          timeout, notify_pseudo_tcp_socket_clock, component);
1203
    } else {
1204
1205
      nice_debug ("Agent %p: component %d pseudo-TCP socket should be "
          "destroyed. Calling priv_pseudo_tcp_error().",
1206
1207
          agent, component->id);
      priv_pseudo_tcp_error (agent, stream, component);
1208
1209
1210
1211
1212
    }
  }
}


1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
void agent_gathering_done (NiceAgent *agent)
{

  GSList *i, *j, *k, *l, *m;

  for (i = agent->streams; i; i = i->next) {
    Stream *stream = i->data;
    for (j = stream->components; j; j = j->next) {
      Component *component = j->data;

      for (k = component->local_candidates; k; k = k->next) {
        NiceCandidate *local_candidate = k->data;
Youness Alaoui's avatar
Youness Alaoui committed
1225
1226
1227
1228
1229
1230
1231
1232
1233
	{
	  gchar tmpbuf[INET6_ADDRSTRLEN];
	  nice_address_to_string (&local_candidate->addr, tmpbuf);
          nice_debug ("Agent %p: gathered local candidate : [%s]:%u"
              " for s%d/c%d. U/P '%s'/'%s'", agent,
              tmpbuf, nice_address_get_port (&local_candidate->addr),
              local_candidate->stream_id, local_candidate->component_id,
              local_candidate->username, local_candidate->password);
	}
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
        for (l = component->remote_candidates; l; l = l->next) {
          NiceCandidate *remote_candidate = l->data;

          for (m = stream->conncheck_list; m; m = m->next) {
            CandidateCheckPair *p = m->data;

            if (p->local == local_candidate && p->remote == remote_candidate)
              break;
          }
          if (m == NULL) {
            conn_check_add_for_candidate (agent, stream->id, component, remote_candidate);
          }
        }
      }
    }
  }

1251
#ifdef HAVE_GUPNP
Youness Alaoui's avatar
Youness Alaoui committed
1252