Version 0.1.0
[sipe-libnice.git] / agent / agent.c
blob8eedc0c31328951a08cf118e14273c7740f6b32f
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2006-2010 Collabora Ltd.
5 * Contact: Youness Alaoui
6 * (C) 2006-2010 Nokia Corporation. All rights reserved.
7 * Contact: Kai Vehmanen
9 * The contents of this file are subject to the Mozilla Public License Version
10 * 1.1 (the "License"); you may not use this file except in compliance with
11 * the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS" basis,
15 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 * for the specific language governing rights and limitations under the
17 * License.
19 * The Original Code is the Nice GLib ICE library.
21 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
22 * Corporation. All Rights Reserved.
24 * Contributors:
25 * Dafydd Harries, Collabora Ltd.
26 * Youness Alaoui, Collabora Ltd.
27 * Kai Vehmanen, Nokia
29 * Alternatively, the contents of this file may be used under the terms of the
30 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
31 * case the provisions of LGPL are applicable instead of those above. If you
32 * wish to allow use of your version of this file only under the terms of the
33 * LGPL and not to allow others to use your version of this file under the
34 * MPL, indicate your decision by deleting the provisions above and replace
35 * them with the notice and other provisions required by the LGPL. If you do
36 * not delete the provisions above, a recipient may use your version of this
37 * file under either the MPL or the LGPL.
41 #ifdef HAVE_CONFIG_H
42 # include <config.h>
43 #else
44 #define NICEAPI_EXPORT
45 #endif
47 #include <glib.h>
49 #include <string.h>
50 #include <errno.h>
52 #ifdef G_OS_WIN32
53 #include <winsock2.h>
54 #else
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
58 #endif
60 #include "debug.h"
62 #include "socket.h"
63 #include "stun/usages/turn.h"
64 #include "candidate.h"
65 #include "component.h"
66 #include "conncheck.h"
67 #include "discovery.h"
68 #include "agent.h"
69 #include "agent-priv.h"
70 #include "agent-signals-marshal.h"
72 #include "stream.h"
73 #include "interfaces.h"
75 #include "pseudotcp.h"
77 /* This is the max size of a UDP packet
78 * will it work tcp relaying??
80 #define MAX_BUFFER_SIZE 65536
81 #define DEFAULT_STUN_PORT 3478
82 #define DEFAULT_UPNP_TIMEOUT 200
84 #define MAX_TCP_MTU 1400 /* Use 1400 because of VPNs and we assume IEE 802.3 */
86 G_DEFINE_TYPE (NiceAgent, nice_agent, G_TYPE_OBJECT);
88 enum
90 PROP_COMPATIBILITY = 1,
91 PROP_MAIN_CONTEXT,
92 PROP_STUN_SERVER,
93 PROP_STUN_SERVER_PORT,
94 PROP_CONTROLLING_MODE,
95 PROP_FULL_MODE,
96 PROP_STUN_PACING_TIMER,
97 PROP_MAX_CONNECTIVITY_CHECKS,
98 PROP_PROXY_TYPE,
99 PROP_PROXY_IP,
100 PROP_PROXY_PORT,
101 PROP_PROXY_USERNAME,
102 PROP_PROXY_PASSWORD,
103 PROP_UPNP,
104 PROP_UPNP_TIMEOUT,
105 PROP_RELIABLE
109 enum
111 SIGNAL_COMPONENT_STATE_CHANGED,
112 SIGNAL_CANDIDATE_GATHERING_DONE,
113 SIGNAL_NEW_SELECTED_PAIR,
114 SIGNAL_NEW_CANDIDATE,
115 SIGNAL_NEW_REMOTE_CANDIDATE,
116 SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED,
117 SIGNAL_RELIABLE_TRANSPORT_WRITABLE,
118 N_SIGNALS,
121 static guint signals[N_SIGNALS];
123 static GStaticRecMutex agent_mutex = G_STATIC_REC_MUTEX_INIT; /* Mutex used for thread-safe lib */
125 static gboolean priv_attach_stream_component (NiceAgent *agent,
126 Stream *stream,
127 Component *component);
128 static void priv_detach_stream_component (Stream *stream, Component *component);
130 static void priv_free_upnp (NiceAgent *agent);
133 void agent_lock (void)
135 g_static_rec_mutex_lock (&agent_mutex);
138 void agent_unlock (void)
140 g_static_rec_mutex_unlock (&agent_mutex);
145 StunUsageIceCompatibility
146 agent_to_ice_compatibility (NiceAgent *agent)
148 return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
149 STUN_USAGE_ICE_COMPATIBILITY_GOOGLE :
150 agent->compatibility == NICE_COMPATIBILITY_MSN ?
151 STUN_USAGE_ICE_COMPATIBILITY_MSN :
152 agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
153 STUN_USAGE_ICE_COMPATIBILITY_WLM2009 :
154 agent->compatibility == NICE_COMPATIBILITY_OC2007 ?
155 STUN_USAGE_ICE_COMPATIBILITY_MSN :
156 agent->compatibility == NICE_COMPATIBILITY_OC2007R2 ?
157 STUN_USAGE_ICE_COMPATIBILITY_WLM2009 :
158 STUN_USAGE_ICE_COMPATIBILITY_RFC5245;
162 StunUsageTurnCompatibility
163 agent_to_turn_compatibility (NiceAgent *agent)
165 return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
166 STUN_USAGE_TURN_COMPATIBILITY_GOOGLE :
167 agent->compatibility == NICE_COMPATIBILITY_MSN ?
168 STUN_USAGE_TURN_COMPATIBILITY_MSN :
169 agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
170 STUN_USAGE_TURN_COMPATIBILITY_MSN :
171 agent->compatibility == NICE_COMPATIBILITY_OC2007 ?
172 STUN_USAGE_TURN_COMPATIBILITY_OC2007 :
173 agent->compatibility == NICE_COMPATIBILITY_OC2007R2 ?
174 STUN_USAGE_TURN_COMPATIBILITY_OC2007 :
175 STUN_USAGE_TURN_COMPATIBILITY_RFC5766;
178 NiceTurnSocketCompatibility
179 agent_to_turn_socket_compatibility (NiceAgent *agent)
181 return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
182 NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE :
183 agent->compatibility == NICE_COMPATIBILITY_MSN ?
184 NICE_TURN_SOCKET_COMPATIBILITY_MSN :
185 agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
186 NICE_TURN_SOCKET_COMPATIBILITY_MSN :
187 agent->compatibility == NICE_COMPATIBILITY_OC2007 ?
188 NICE_TURN_SOCKET_COMPATIBILITY_OC2007 :
189 agent->compatibility == NICE_COMPATIBILITY_OC2007R2 ?
190 NICE_TURN_SOCKET_COMPATIBILITY_OC2007 :
191 NICE_TURN_SOCKET_COMPATIBILITY_RFC5766;
194 Stream *agent_find_stream (NiceAgent *agent, guint stream_id)
196 GSList *i;
198 for (i = agent->streams; i; i = i->next)
200 Stream *s = i->data;
202 if (s->id == stream_id)
203 return s;
206 return NULL;
210 gboolean
211 agent_find_component (
212 NiceAgent *agent,
213 guint stream_id,
214 guint component_id,
215 Stream **stream,
216 Component **component)
218 Stream *s;
219 Component *c;
221 s = agent_find_stream (agent, stream_id);
223 if (s == NULL)
224 return FALSE;
226 c = stream_find_component_by_id (s, component_id);
228 if (c == NULL)
229 return FALSE;
231 if (stream)
232 *stream = s;
234 if (component)
235 *component = c;
237 return TRUE;
241 static void
242 nice_agent_dispose (GObject *object);
244 static void
245 nice_agent_get_property (
246 GObject *object,
247 guint property_id,
248 GValue *value,
249 GParamSpec *pspec);
251 static void
252 nice_agent_set_property (
253 GObject *object,
254 guint property_id,
255 const GValue *value,
256 GParamSpec *pspec);
259 static void
260 nice_agent_class_init (NiceAgentClass *klass)
262 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
264 gobject_class->get_property = nice_agent_get_property;
265 gobject_class->set_property = nice_agent_set_property;
266 gobject_class->dispose = nice_agent_dispose;
268 /* install properties */
270 * NiceAgent:main-context:
272 * A GLib main context is needed for all timeouts used by libnice.
273 * This is a property being set by the nice_agent_new() call.
275 g_object_class_install_property (gobject_class, PROP_MAIN_CONTEXT,
276 g_param_spec_pointer (
277 "main-context",
278 "The GMainContext to use for timeouts",
279 "The GMainContext to use for timeouts",
280 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
283 * NiceAgent:compatibility:
285 * The Nice agent can work in various compatibility modes depending on
286 * what the application/peer needs.
287 * <para> See also: #NiceCompatibility</para>
289 g_object_class_install_property (gobject_class, PROP_COMPATIBILITY,
290 g_param_spec_uint (
291 "compatibility",
292 "ICE specification compatibility",
293 "The compatibility mode for the agent",
294 NICE_COMPATIBILITY_RFC5245, NICE_COMPATIBILITY_LAST,
295 NICE_COMPATIBILITY_RFC5245,
296 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
298 g_object_class_install_property (gobject_class, PROP_STUN_SERVER,
299 g_param_spec_string (
300 "stun-server",
301 "STUN server IP address",
302 "The IP address (not the hostname) of the STUN server to use",
303 NULL,
304 G_PARAM_READWRITE));
306 g_object_class_install_property (gobject_class, PROP_STUN_SERVER_PORT,
307 g_param_spec_uint (
308 "stun-server-port",
309 "STUN server port",
310 "Port of the STUN server used to gather server-reflexive candidates",
311 1, 65536,
312 1, /* not a construct property, ignored */
313 G_PARAM_READWRITE));
315 g_object_class_install_property (gobject_class, PROP_CONTROLLING_MODE,
316 g_param_spec_boolean (
317 "controlling-mode",
318 "ICE controlling mode",
319 "Whether the agent is in controlling mode",
320 FALSE, /* not a construct property, ignored */
321 G_PARAM_READWRITE));
323 g_object_class_install_property (gobject_class, PROP_FULL_MODE,
324 g_param_spec_boolean (
325 "full-mode",
326 "ICE full mode",
327 "Whether agent runs in ICE full mode",
328 TRUE, /* use full mode by default */
329 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
331 g_object_class_install_property (gobject_class, PROP_STUN_PACING_TIMER,
332 g_param_spec_uint (
333 "stun-pacing-timer",
334 "STUN pacing timer",
335 "Timer 'Ta' (msecs) used in the IETF ICE specification for pacing "
336 "candidate gathering and sending of connectivity checks",
337 1, 0xffffffff,
338 NICE_AGENT_TIMER_TA_DEFAULT,
339 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
341 /* note: according to spec recommendation in sect 5.7.3 (ID-19) */
342 g_object_class_install_property (gobject_class, PROP_MAX_CONNECTIVITY_CHECKS,
343 g_param_spec_uint (
344 "max-connectivity-checks",
345 "Maximum number of connectivity checks",
346 "Upper limit for the total number of connectivity checks performed",
347 0, 0xffffffff,
348 0, /* default set in init */
349 G_PARAM_READWRITE));
352 * NiceAgent:proxy-ip:
354 * The proxy server IP used to bypass a proxy firewall
356 * Since: 0.0.4
358 g_object_class_install_property (gobject_class, PROP_PROXY_IP,
359 g_param_spec_string (
360 "proxy-ip",
361 "Proxy server IP",
362 "The proxy server IP used to bypass a proxy firewall",
363 NULL,
364 G_PARAM_READWRITE));
367 * NiceAgent:proxy-port:
369 * The proxy server port used to bypass a proxy firewall
371 * Since: 0.0.4
373 g_object_class_install_property (gobject_class, PROP_PROXY_PORT,
374 g_param_spec_uint (
375 "proxy-port",
376 "Proxy server port",
377 "The Proxy server port used to bypass a proxy firewall",
378 1, 65536,
380 G_PARAM_READWRITE));
383 * NiceAgent:proxy-type:
385 * The type of proxy set in the proxy-ip property
387 * Since: 0.0.4
389 g_object_class_install_property (gobject_class, PROP_PROXY_TYPE,
390 g_param_spec_uint (
391 "proxy-type",
392 "Type of proxy to use",
393 "The type of proxy set in the proxy-ip property",
394 NICE_PROXY_TYPE_NONE, NICE_PROXY_TYPE_LAST,
395 NICE_PROXY_TYPE_NONE,
396 G_PARAM_READWRITE));
399 * NiceAgent:proxy-username:
401 * The username used to authenticate with the proxy
403 * Since: 0.0.4
405 g_object_class_install_property (gobject_class, PROP_PROXY_USERNAME,
406 g_param_spec_string (
407 "proxy-username",
408 "Proxy server username",
409 "The username used to authenticate with the proxy",
410 NULL,
411 G_PARAM_READWRITE));
414 * NiceAgent:proxy-password:
416 * The password used to authenticate with the proxy
418 * Since: 0.0.4
420 g_object_class_install_property (gobject_class, PROP_PROXY_PASSWORD,
421 g_param_spec_string (
422 "proxy-password",
423 "Proxy server password",
424 "The password used to authenticate with the proxy",
425 NULL,
426 G_PARAM_READWRITE));
429 * NiceAgent:upnp:
431 * Whether the agent should use UPnP to open a port in the router and
432 * get the external IP
434 * Since: 0.0.7
436 g_object_class_install_property (gobject_class, PROP_UPNP,
437 g_param_spec_boolean (
438 "upnp",
439 #ifdef HAVE_GUPNP
440 "Use UPnP",
441 "Whether the agent should use UPnP to open a port in the router and "
442 "get the external IP",
443 #else
444 "Use UPnP (disabled in build)",
445 "Does nothing because libnice was not built with UPnP support",
446 #endif
447 TRUE, /* enable UPnP by default */
448 G_PARAM_READWRITE| G_PARAM_CONSTRUCT));
451 * NiceAgent:upnp-timeout:
453 * The maximum amount of time to wait for UPnP discovery to finish before
454 * signaling the #NiceAgent::candidate-gathering-done signal
456 * Since: 0.0.7
458 g_object_class_install_property (gobject_class, PROP_UPNP_TIMEOUT,
459 g_param_spec_uint (
460 "upnp-timeout",
461 #ifdef HAVE_GUPNP
462 "Timeout for UPnP discovery",
463 "The maximum amount of time to wait for UPnP discovery to finish before "
464 "signaling the candidate-gathering-done signal",
465 #else
466 "Timeout for UPnP discovery (disabled in build)",
467 "Does nothing because libnice was not built with UPnP support",
468 #endif
469 100, 60000,
470 DEFAULT_UPNP_TIMEOUT,
471 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
474 * NiceAgent:reliable:
476 * Whether the agent should use PseudoTcp to ensure a reliable transport
477 * of messages
479 * Since: 0.0.11
481 g_object_class_install_property (gobject_class, PROP_RELIABLE,
482 g_param_spec_boolean (
483 "reliable",
484 "reliable mode",
485 "Whether the agent should use PseudoTcp to ensure a reliable transport"
486 "of messages",
487 FALSE,
488 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
490 /* install signals */
493 * NiceAgent::component-state-changed
494 * @agent: The #NiceAgent object
495 * @stream_id: The ID of the stream
496 * @component_id: The ID of the component
497 * @state: The #NiceComponentState of the component
499 * This signal is fired whenever a component's state changes
501 signals[SIGNAL_COMPONENT_STATE_CHANGED] =
502 g_signal_new (
503 "component-state-changed",
504 G_OBJECT_CLASS_TYPE (klass),
505 G_SIGNAL_RUN_LAST,
507 NULL,
508 NULL,
509 agent_marshal_VOID__UINT_UINT_UINT,
510 G_TYPE_NONE,
512 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
513 G_TYPE_INVALID);
516 * NiceAgent::candidate-gathering-done:
517 * @agent: The #NiceAgent object
518 * @stream_id: The ID of the stream
520 * This signal is fired whenever a stream has finished gathering its
521 * candidates after a call to nice_agent_gather_candidates()
523 signals[SIGNAL_CANDIDATE_GATHERING_DONE] =
524 g_signal_new (
525 "candidate-gathering-done",
526 G_OBJECT_CLASS_TYPE (klass),
527 G_SIGNAL_RUN_LAST,
529 NULL,
530 NULL,
531 agent_marshal_VOID__UINT,
532 G_TYPE_NONE,
534 G_TYPE_UINT, G_TYPE_INVALID);
537 * NiceAgent::new-selected-pair
538 * @agent: The #NiceAgent object
539 * @stream_id: The ID of the stream
540 * @component_id: The ID of the component
541 * @lfoundation: The local foundation of the selected candidate pair
542 * @rfoundation: The remote foundation of the selected candidate pair
544 * This signal is fired once a candidate pair is selected for data transfer for
545 * a stream's component
547 signals[SIGNAL_NEW_SELECTED_PAIR] =
548 g_signal_new (
549 "new-selected-pair",
550 G_OBJECT_CLASS_TYPE (klass),
551 G_SIGNAL_RUN_LAST,
553 NULL,
554 NULL,
555 agent_marshal_VOID__UINT_UINT_STRING_STRING,
556 G_TYPE_NONE,
558 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING,
559 G_TYPE_INVALID);
562 * NiceAgent::new-candidate
563 * @agent: The #NiceAgent object
564 * @stream_id: The ID of the stream
565 * @component_id: The ID of the component
566 * @foundation: The foundation of the new candidate
568 * This signal is fired when the agent discovers a new candidate
569 * <para> See also: #NiceAgent::candidate-gathering-done </para>
571 signals[SIGNAL_NEW_CANDIDATE] =
572 g_signal_new (
573 "new-candidate",
574 G_OBJECT_CLASS_TYPE (klass),
575 G_SIGNAL_RUN_LAST,
577 NULL,
578 NULL,
579 agent_marshal_VOID__UINT_UINT_STRING,
580 G_TYPE_NONE,
582 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
583 G_TYPE_INVALID);
586 * NiceAgent::new-remote-candidate
587 * @agent: The #NiceAgent object
588 * @stream_id: The ID of the stream
589 * @component_id: The ID of the component
590 * @foundation: The foundation of the new candidate
592 * This signal is fired when the agent discovers a new remote candidate.
593 * This can happen with peer reflexive candidates.
595 signals[SIGNAL_NEW_REMOTE_CANDIDATE] =
596 g_signal_new (
597 "new-remote-candidate",
598 G_OBJECT_CLASS_TYPE (klass),
599 G_SIGNAL_RUN_LAST,
601 NULL,
602 NULL,
603 agent_marshal_VOID__UINT_UINT_STRING,
604 G_TYPE_NONE,
606 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
607 G_TYPE_INVALID);
610 * NiceAgent::initial-binding-request-received
611 * @agent: The #NiceAgent object
612 * @stream_id: The ID of the stream
614 * This signal is fired when we received our first binding request from
615 * the peer.
617 signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED] =
618 g_signal_new (
619 "initial-binding-request-received",
620 G_OBJECT_CLASS_TYPE (klass),
621 G_SIGNAL_RUN_LAST,
623 NULL,
624 NULL,
625 agent_marshal_VOID__UINT,
626 G_TYPE_NONE,
628 G_TYPE_UINT,
629 G_TYPE_INVALID);
632 * NiceAgent::reliable-transport-writable
633 * @agent: The #NiceAgent object
634 * @stream_id: The ID of the stream
635 * @component_id: The ID of the component
637 * This signal is fired on the reliable #NiceAgent when the underlying reliable
638 * transport becomes writable.
639 * This signal is only emitted when the nice_agent_send() function returns less
640 * bytes than requested to send (or -1) and once when the connection
641 * is established.
643 * Since: 0.0.11
645 signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE] =
646 g_signal_new (
647 "reliable-transport-writable",
648 G_OBJECT_CLASS_TYPE (klass),
649 G_SIGNAL_RUN_LAST,
651 NULL,
652 NULL,
653 agent_marshal_VOID__UINT_UINT,
654 G_TYPE_NONE,
656 G_TYPE_UINT, G_TYPE_UINT,
657 G_TYPE_INVALID);
660 /* Init debug options depending on env variables */
661 nice_debug_init ();
664 static void priv_generate_tie_breaker (NiceAgent *agent)
666 nice_rng_generate_bytes (agent->rng, 8, (gchar*)&agent->tie_breaker);
669 static void
670 nice_agent_init (NiceAgent *agent)
672 agent->next_candidate_id = 1;
673 agent->next_stream_id = 1;
675 /* set defaults; not construct params, so set here */
676 agent->stun_server_port = DEFAULT_STUN_PORT;
677 agent->controlling_mode = TRUE;
678 agent->max_conn_checks = NICE_AGENT_MAX_CONNECTIVITY_CHECKS_DEFAULT;
680 agent->discovery_list = NULL;
681 agent->discovery_unsched_items = 0;
682 agent->discovery_timer_source = NULL;
683 agent->conncheck_timer_source = NULL;
684 agent->keepalive_timer_source = NULL;
685 agent->refresh_list = NULL;
686 agent->media_after_tick = FALSE;
687 agent->software_attribute = NULL;
689 agent->compatibility = NICE_COMPATIBILITY_RFC5245;
690 agent->reliable = FALSE;
692 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
693 STUN_COMPATIBILITY_RFC5389,
694 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
695 STUN_AGENT_USAGE_USE_FINGERPRINT);
697 agent->rng = nice_rng_new ();
698 priv_generate_tie_breaker (agent);
702 NICEAPI_EXPORT NiceAgent *
703 nice_agent_new (GMainContext *ctx, NiceCompatibility compat)
705 NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
706 "compatibility", compat,
707 "main-context", ctx,
708 "reliable", FALSE,
709 NULL);
711 return agent;
715 NICEAPI_EXPORT NiceAgent *
716 nice_agent_new_reliable (GMainContext *ctx, NiceCompatibility compat)
718 NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
719 "compatibility", compat,
720 "main-context", ctx,
721 "reliable", TRUE,
722 NULL);
724 return agent;
728 static void
729 nice_agent_get_property (
730 GObject *object,
731 guint property_id,
732 GValue *value,
733 GParamSpec *pspec)
735 NiceAgent *agent = NICE_AGENT (object);
737 agent_lock();
739 switch (property_id)
741 case PROP_MAIN_CONTEXT:
742 g_value_set_pointer (value, agent->main_context);
743 break;
745 case PROP_COMPATIBILITY:
746 g_value_set_uint (value, agent->compatibility);
747 break;
749 case PROP_STUN_SERVER:
750 g_value_set_string (value, agent->stun_server_ip);
751 break;
753 case PROP_STUN_SERVER_PORT:
754 g_value_set_uint (value, agent->stun_server_port);
755 break;
757 case PROP_CONTROLLING_MODE:
758 g_value_set_boolean (value, agent->controlling_mode);
759 break;
761 case PROP_FULL_MODE:
762 g_value_set_boolean (value, agent->full_mode);
763 break;
765 case PROP_STUN_PACING_TIMER:
766 g_value_set_uint (value, agent->timer_ta);
767 break;
769 case PROP_MAX_CONNECTIVITY_CHECKS:
770 g_value_set_uint (value, agent->max_conn_checks);
771 /* XXX: should we prune the list of already existing checks? */
772 break;
774 case PROP_PROXY_IP:
775 g_value_set_string (value, agent->proxy_ip);
776 break;
778 case PROP_PROXY_PORT:
779 g_value_set_uint (value, agent->proxy_port);
780 break;
782 case PROP_PROXY_TYPE:
783 g_value_set_uint (value, agent->proxy_type);
784 break;
786 case PROP_PROXY_USERNAME:
787 g_value_set_string (value, agent->proxy_username);
788 break;
790 case PROP_PROXY_PASSWORD:
791 g_value_set_string (value, agent->proxy_password);
792 break;
794 case PROP_UPNP:
795 #ifdef HAVE_GUPNP
796 g_value_set_boolean (value, agent->upnp_enabled);
797 #else
798 g_value_set_boolean (value, FALSE);
799 #endif
800 break;
802 case PROP_UPNP_TIMEOUT:
803 #ifdef HAVE_GUPNP
804 g_value_set_uint (value, agent->upnp_timeout);
805 #else
806 g_value_set_uint (value, DEFAULT_UPNP_TIMEOUT);
807 #endif
808 break;
810 case PROP_RELIABLE:
811 g_value_set_boolean (value, agent->reliable);
812 break;
814 default:
815 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
818 agent_unlock();
822 static void
823 nice_agent_set_property (
824 GObject *object,
825 guint property_id,
826 const GValue *value,
827 GParamSpec *pspec)
829 NiceAgent *agent = NICE_AGENT (object);
831 agent_lock();
833 switch (property_id)
835 case PROP_MAIN_CONTEXT:
836 agent->main_context = g_value_get_pointer (value);
837 if (agent->main_context != NULL)
838 g_main_context_ref (agent->main_context);
839 break;
841 case PROP_COMPATIBILITY:
842 agent->compatibility = g_value_get_uint (value);
843 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
844 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
845 STUN_COMPATIBILITY_RFC3489,
846 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
847 STUN_AGENT_USAGE_IGNORE_CREDENTIALS);
848 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN) {
849 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
850 STUN_COMPATIBILITY_RFC3489,
851 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
852 STUN_AGENT_USAGE_FORCE_VALIDATER);
853 } else if (agent->compatibility == NICE_COMPATIBILITY_WLM2009) {
854 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
855 STUN_COMPATIBILITY_WLM2009,
856 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
857 STUN_AGENT_USAGE_USE_FINGERPRINT);
858 } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007) {
859 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
860 STUN_COMPATIBILITY_RFC3489,
861 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
862 STUN_AGENT_USAGE_FORCE_VALIDATER |
863 STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES);
864 } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
865 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
866 STUN_COMPATIBILITY_WLM2009,
867 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
868 STUN_AGENT_USAGE_USE_FINGERPRINT |
869 STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES);
870 } else {
871 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
872 STUN_COMPATIBILITY_RFC5389,
873 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
874 STUN_AGENT_USAGE_USE_FINGERPRINT);
876 stun_agent_set_software (&agent->stun_agent, agent->software_attribute);
878 break;
880 case PROP_STUN_SERVER:
881 g_free (agent->stun_server_ip);
882 agent->stun_server_ip = g_value_dup_string (value);
883 break;
885 case PROP_STUN_SERVER_PORT:
886 agent->stun_server_port = g_value_get_uint (value);
887 break;
889 case PROP_CONTROLLING_MODE:
890 agent->controlling_mode = g_value_get_boolean (value);
891 break;
893 case PROP_FULL_MODE:
894 agent->full_mode = g_value_get_boolean (value);
895 break;
897 case PROP_STUN_PACING_TIMER:
898 agent->timer_ta = g_value_get_uint (value);
899 break;
901 case PROP_MAX_CONNECTIVITY_CHECKS:
902 agent->max_conn_checks = g_value_get_uint (value);
903 break;
905 case PROP_PROXY_IP:
906 g_free (agent->proxy_ip);
907 agent->proxy_ip = g_value_dup_string (value);
908 break;
910 case PROP_PROXY_PORT:
911 agent->proxy_port = g_value_get_uint (value);
912 break;
914 case PROP_PROXY_TYPE:
915 agent->proxy_type = g_value_get_uint (value);
916 break;
918 case PROP_PROXY_USERNAME:
919 g_free (agent->proxy_username);
920 agent->proxy_username = g_value_dup_string (value);
921 break;
923 case PROP_PROXY_PASSWORD:
924 g_free (agent->proxy_password);
925 agent->proxy_password = g_value_dup_string (value);
926 break;
928 case PROP_UPNP_TIMEOUT:
929 #ifdef HAVE_GUPNP
930 agent->upnp_timeout = g_value_get_uint (value);
931 #endif
932 break;
934 case PROP_UPNP:
935 #ifdef HAVE_GUPNP
936 agent->upnp_enabled = g_value_get_boolean (value);
937 #endif
938 break;
940 case PROP_RELIABLE:
941 agent->reliable = g_value_get_boolean (value);
942 break;
944 default:
945 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
948 agent_unlock();
953 static void priv_destroy_component_tcp (Component *component)
955 if (component->tcp_clock) {
956 g_source_destroy (component->tcp_clock);
957 g_source_unref (component->tcp_clock);
958 component->tcp_clock = NULL;
960 if (component->tcp) {
961 pseudo_tcp_socket_close (component->tcp, TRUE);
962 g_object_unref (component->tcp);
963 component->tcp = NULL;
965 if (component->tcp_data != NULL) {
966 g_slice_free (TcpUserData, component->tcp_data);
967 component->tcp_data = NULL;
971 static void priv_pseudo_tcp_error (NiceAgent *agent, Stream *stream,
972 Component *component)
974 if (component->tcp) {
975 agent_signal_component_state_change (agent, stream->id,
976 component->id, NICE_COMPONENT_STATE_FAILED);
977 priv_detach_stream_component (stream, component);
979 priv_destroy_component_tcp (component);
982 static void
983 adjust_tcp_clock (NiceAgent *agent, Stream *stream, Component *component);
986 static void
987 pseudo_tcp_socket_opened (PseudoTcpSocket *sock, gpointer user_data)
989 TcpUserData *data = (TcpUserData *)user_data;
990 NiceAgent *agent = data->agent;
991 Component *component = data->component;
992 Stream *stream = data->stream;
994 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket Opened", data->agent,
995 stream->id, component->id);
996 g_signal_emit (agent, signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE], 0,
997 stream->id, component->id);
1000 static void
1001 pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data)
1003 TcpUserData *data = (TcpUserData *)user_data;
1004 NiceAgent *agent = data->agent;
1005 Component *component = data->component;
1006 Stream *stream = data->stream;
1007 gchar buf[MAX_BUFFER_SIZE];
1008 gint len;
1010 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket readable", agent,
1011 stream->id, component->id);
1013 component->tcp_readable = TRUE;
1015 g_object_add_weak_pointer (G_OBJECT (sock), (gpointer *)&sock);
1016 g_object_add_weak_pointer (G_OBJECT (agent), (gpointer *)&agent);
1018 do {
1019 if (component->g_source_io_cb)
1020 len = pseudo_tcp_socket_recv (sock, buf, sizeof(buf));
1021 else
1022 len = 0;
1024 if (len > 0) {
1025 gpointer data = component->data;
1026 gint sid = stream->id;
1027 gint cid = component->id;
1028 NiceAgentRecvFunc callback = component->g_source_io_cb;
1029 /* Unlock the agent before calling the callback */
1030 agent_unlock();
1031 callback (agent, sid, cid, len, buf, data);
1032 agent_lock();
1033 if (sock == NULL) {
1034 nice_debug ("PseudoTCP socket got destroyed in readable callback!");
1035 break;
1037 } else if (len < 0 &&
1038 pseudo_tcp_socket_get_error (sock) != EWOULDBLOCK) {
1039 /* Signal error */
1040 priv_pseudo_tcp_error (agent, stream, component);
1041 } else if (len < 0 &&
1042 pseudo_tcp_socket_get_error (sock) == EWOULDBLOCK){
1043 component->tcp_readable = FALSE;
1045 } while (len > 0);
1047 if (agent) {
1048 adjust_tcp_clock (agent, stream, component);
1049 g_object_remove_weak_pointer (G_OBJECT (agent), (gpointer *)&agent);
1050 } else {
1051 nice_debug ("Not calling adjust_tcp_clock.. agent got destroyed!");
1053 if (sock)
1054 g_object_remove_weak_pointer (G_OBJECT (sock), (gpointer *)&sock);
1057 static void
1058 pseudo_tcp_socket_writable (PseudoTcpSocket *sock, gpointer user_data)
1060 TcpUserData *data = (TcpUserData *)user_data;
1061 NiceAgent *agent = data->agent;
1062 Component *component = data->component;
1063 Stream *stream = data->stream;
1065 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket writable", data->agent,
1066 data->stream->id, data->component->id);
1067 g_signal_emit (agent, signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE], 0,
1068 stream->id, component->id);
1071 static void
1072 pseudo_tcp_socket_closed (PseudoTcpSocket *sock, guint32 err,
1073 gpointer user_data)
1075 TcpUserData *data = (TcpUserData *)user_data;
1076 NiceAgent *agent = data->agent;
1077 Component *component = data->component;
1078 Stream *stream = data->stream;
1080 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket closed", agent,
1081 stream->id, component->id);
1082 priv_pseudo_tcp_error (agent, stream, component);
1086 static PseudoTcpWriteResult
1087 pseudo_tcp_socket_write_packet (PseudoTcpSocket *sock,
1088 const gchar *buffer, guint32 len, gpointer user_data)
1090 TcpUserData *data = (TcpUserData *)user_data;
1091 Component *component = data->component;
1093 if (component->selected_pair.local != NULL) {
1094 NiceSocket *sock;
1095 NiceAddress *addr;
1097 #ifndef NDEBUG
1098 gchar tmpbuf[INET6_ADDRSTRLEN];
1099 nice_address_to_string (&component->selected_pair.remote->addr, tmpbuf);
1101 nice_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", data->agent,
1102 data->stream->id, component->id, len, tmpbuf,
1103 nice_address_get_port (&component->selected_pair.remote->addr));
1104 #endif
1106 sock = component->selected_pair.local->sockptr;
1107 addr = &component->selected_pair.remote->addr;
1108 if (nice_socket_send (sock, addr, len, buffer)) {
1109 return WR_SUCCESS;
1113 return WR_FAIL;
1117 static gboolean
1118 notify_pseudo_tcp_socket_clock (gpointer user_data)
1120 TcpUserData *data = (TcpUserData *)user_data;
1121 Component *component = data->component;
1122 Stream *stream = data->stream;
1123 NiceAgent *agent = data->agent;
1125 agent_lock();
1127 if (g_source_is_destroyed (g_main_current_source ())) {
1128 nice_debug ("Source was destroyed. "
1129 "Avoided race condition in notify_pseudo_tcp_socket_clock");
1130 agent_unlock ();
1131 return FALSE;
1133 if (component->tcp_clock) {
1134 g_source_destroy (component->tcp_clock);
1135 g_source_unref (component->tcp_clock);
1136 component->tcp_clock = NULL;
1139 pseudo_tcp_socket_notify_clock (component->tcp);
1140 adjust_tcp_clock (agent, stream, component);
1142 agent_unlock();
1144 return FALSE;
1147 static void
1148 adjust_tcp_clock (NiceAgent *agent, Stream *stream, Component *component)
1150 long timeout = 0;
1151 if (component->tcp) {
1152 if (pseudo_tcp_socket_get_next_clock (component->tcp, &timeout)) {
1153 if (component->tcp_clock) {
1154 g_source_destroy (component->tcp_clock);
1155 g_source_unref (component->tcp_clock);
1156 component->tcp_clock = NULL;
1158 component->tcp_clock = agent_timeout_add_with_context (agent,
1159 timeout, notify_pseudo_tcp_socket_clock, component->tcp_data);
1160 } else {
1161 nice_debug ("Agent %p: component %d pseudo tcp socket should be destroyed",
1162 agent, component->id);
1163 priv_pseudo_tcp_error (agent, stream, component);
1169 void agent_gathering_done (NiceAgent *agent)
1172 GSList *i, *j, *k, *l, *m;
1174 for (i = agent->streams; i; i = i->next) {
1175 Stream *stream = i->data;
1176 for (j = stream->components; j; j = j->next) {
1177 Component *component = j->data;
1179 for (k = component->local_candidates; k; k = k->next) {
1180 NiceCandidate *local_candidate = k->data;
1182 gchar tmpbuf[INET6_ADDRSTRLEN];
1183 nice_address_to_string (&local_candidate->addr, tmpbuf);
1184 nice_debug ("Agent %p: gathered local candidate : [%s]:%u"
1185 " for s%d/c%d. U/P '%s'/'%s'", agent,
1186 tmpbuf, nice_address_get_port (&local_candidate->addr),
1187 local_candidate->stream_id, local_candidate->component_id,
1188 local_candidate->username, local_candidate->password);
1190 for (l = component->remote_candidates; l; l = l->next) {
1191 NiceCandidate *remote_candidate = l->data;
1193 for (m = stream->conncheck_list; m; m = m->next) {
1194 CandidateCheckPair *p = m->data;
1196 if (p->local == local_candidate && p->remote == remote_candidate)
1197 break;
1199 if (m == NULL) {
1200 conn_check_add_for_candidate (agent, stream->id, component, remote_candidate);
1207 #ifdef HAVE_GUPNP
1208 if (agent->discovery_timer_source == NULL &&
1209 agent->upnp_timer_source == NULL) {
1210 agent_signal_gathering_done (agent);
1212 #else
1213 agent_signal_gathering_done (agent);
1214 #endif
1217 void agent_signal_gathering_done (NiceAgent *agent)
1219 GSList *i;
1221 for (i = agent->streams; i; i = i->next) {
1222 Stream *stream = i->data;
1223 if (stream->gathering) {
1224 stream->gathering = FALSE;
1225 g_signal_emit (agent, signals[SIGNAL_CANDIDATE_GATHERING_DONE], 0, stream->id);
1230 void agent_signal_initial_binding_request_received (NiceAgent *agent, Stream *stream)
1232 if (stream->initial_binding_request_received != TRUE) {
1233 stream->initial_binding_request_received = TRUE;
1234 g_signal_emit (agent, signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED], 0, stream->id);
1238 void agent_signal_new_selected_pair (NiceAgent *agent, guint stream_id, guint component_id, const gchar *local_foundation, const gchar *remote_foundation)
1240 Component *component;
1241 Stream *stream;
1242 gchar *lf_copy;
1243 gchar *rf_copy;
1245 if (!agent_find_component (agent, stream_id, component_id,
1246 &stream, &component))
1247 return;
1249 if (component->selected_pair.local->type == NICE_CANDIDATE_TYPE_RELAYED) {
1250 nice_turn_socket_set_peer (component->selected_pair.local->sockptr,
1251 &component->selected_pair.remote->addr);
1254 if (component->tcp) {
1255 pseudo_tcp_socket_connect (component->tcp);
1256 pseudo_tcp_socket_notify_mtu (component->tcp, MAX_TCP_MTU);
1257 adjust_tcp_clock (agent, stream, component);
1258 } else if(agent->reliable) {
1259 nice_debug ("New selected pair received when pseudo tcp socket in error");
1260 return;
1263 lf_copy = g_strdup (local_foundation);
1264 rf_copy = g_strdup (remote_foundation);
1266 g_signal_emit (agent, signals[SIGNAL_NEW_SELECTED_PAIR], 0,
1267 stream_id, component_id, lf_copy, rf_copy);
1269 g_free (lf_copy);
1270 g_free (rf_copy);
1273 void agent_signal_new_candidate (NiceAgent *agent, NiceCandidate *candidate)
1275 g_signal_emit (agent, signals[SIGNAL_NEW_CANDIDATE], 0,
1276 candidate->stream_id,
1277 candidate->component_id,
1278 candidate->foundation);
1281 void agent_signal_new_remote_candidate (NiceAgent *agent, NiceCandidate *candidate)
1283 g_signal_emit (agent, signals[SIGNAL_NEW_REMOTE_CANDIDATE], 0,
1284 candidate->stream_id,
1285 candidate->component_id,
1286 candidate->foundation);
1289 void agent_signal_component_state_change (NiceAgent *agent, guint stream_id, guint component_id, NiceComponentState state)
1291 Component *component;
1292 Stream *stream;
1294 if (!agent_find_component (agent, stream_id, component_id,
1295 &stream, &component))
1296 return;
1298 if (agent->reliable && component->tcp == NULL &&
1299 state != NICE_COMPONENT_STATE_FAILED) {
1300 nice_debug ("Agent %p: not changing component state for s%d:%d to %d "
1301 "because pseudo tcp socket does not exist in reliable mode", agent,
1302 stream->id, component->id, state);
1303 return;
1306 if (component->state != state && state < NICE_COMPONENT_STATE_LAST) {
1307 nice_debug ("Agent %p : stream %u component %u STATE-CHANGE %u -> %u.", agent,
1308 stream_id, component_id, component->state, state);
1310 component->state = state;
1312 g_signal_emit (agent, signals[SIGNAL_COMPONENT_STATE_CHANGED], 0,
1313 stream_id, component_id, state);
1317 guint64
1318 agent_candidate_pair_priority (NiceAgent *agent, NiceCandidate *local, NiceCandidate *remote)
1320 if (agent->controlling_mode)
1321 return nice_candidate_pair_priority (local->priority, remote->priority);
1322 else
1323 return nice_candidate_pair_priority (remote->priority, local->priority);
1326 static void
1327 priv_add_new_candidate_discovery_stun (NiceAgent *agent,
1328 NiceSocket *socket, NiceAddress server,
1329 Stream *stream, guint component_id)
1331 CandidateDiscovery *cdisco;
1333 /* note: no need to check for redundant candidates, as this is
1334 * done later on in the process */
1336 cdisco = g_slice_new0 (CandidateDiscovery);
1338 cdisco->type = NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE;
1339 cdisco->nicesock = socket;
1340 cdisco->server = server;
1341 cdisco->stream = stream;
1342 cdisco->component = stream_find_component_by_id (stream, component_id);
1343 cdisco->agent = agent;
1344 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1345 STUN_COMPATIBILITY_RFC3489,
1346 (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
1347 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) ?
1348 STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES : 0);
1350 nice_debug ("Agent %p : Adding new srv-rflx candidate discovery %p\n",
1351 agent, cdisco);
1353 agent->discovery_list = g_slist_append (agent->discovery_list, cdisco);
1354 ++agent->discovery_unsched_items;
1357 static void
1358 priv_add_new_candidate_discovery_turn (NiceAgent *agent,
1359 NiceSocket *socket, TurnServer *turn,
1360 Stream *stream, guint component_id)
1362 CandidateDiscovery *cdisco;
1363 Component *component = stream_find_component_by_id (stream, component_id);
1365 /* note: no need to check for redundant candidates, as this is
1366 * done later on in the process */
1368 cdisco = g_slice_new0 (CandidateDiscovery);
1369 cdisco->type = NICE_CANDIDATE_TYPE_RELAYED;
1371 if (turn->type == NICE_RELAY_TYPE_TURN_UDP) {
1372 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
1373 NiceAddress addr = socket->addr;
1374 NiceSocket *new_socket;
1375 nice_address_set_port (&addr, 0);
1377 new_socket = nice_udp_bsd_socket_new (&addr);
1378 if (new_socket) {
1379 _priv_set_socket_tos (agent, new_socket, stream->tos);
1380 agent_attach_stream_component_socket (agent, stream,
1381 component, new_socket);
1382 component->sockets= g_slist_append (component->sockets, new_socket);
1383 socket = new_socket;
1386 cdisco->nicesock = socket;
1387 } else {
1388 NiceAddress proxy_server;
1389 socket = NULL;
1391 if (agent->proxy_type != NICE_PROXY_TYPE_NONE &&
1392 agent->proxy_ip != NULL &&
1393 nice_address_set_from_string (&proxy_server, agent->proxy_ip)) {
1394 nice_address_set_port (&proxy_server, agent->proxy_port);
1395 socket = nice_tcp_bsd_socket_new (agent, component->ctx, &proxy_server);
1397 if (socket) {
1398 _priv_set_socket_tos (agent, socket, stream->tos);
1399 if (agent->proxy_type == NICE_PROXY_TYPE_SOCKS5) {
1400 socket = nice_socks5_socket_new (socket, &turn->server,
1401 agent->proxy_username, agent->proxy_password);
1402 } else if (agent->proxy_type == NICE_PROXY_TYPE_HTTP){
1403 socket = nice_http_socket_new (socket, &turn->server,
1404 agent->proxy_username, agent->proxy_password);
1405 } else {
1406 nice_socket_free (socket);
1407 socket = NULL;
1412 if (socket == NULL) {
1413 socket = nice_tcp_bsd_socket_new (agent, component->ctx, &turn->server);
1414 _priv_set_socket_tos (agent, socket, stream->tos);
1416 if (turn->type == NICE_RELAY_TYPE_TURN_TLS &&
1417 agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
1418 socket = nice_pseudossl_socket_new (agent, socket);
1420 cdisco->nicesock = nice_tcp_turn_socket_new (agent, socket,
1421 agent_to_turn_socket_compatibility (agent));
1423 agent_attach_stream_component_socket (agent, stream,
1424 component, cdisco->nicesock);
1425 component->sockets = g_slist_append (component->sockets, cdisco->nicesock);
1428 cdisco->turn = turn;
1429 cdisco->server = turn->server;
1431 cdisco->stream = stream;
1432 cdisco->component = stream_find_component_by_id (stream, component_id);
1433 cdisco->agent = agent;
1435 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
1436 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1437 STUN_COMPATIBILITY_RFC3489,
1438 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
1439 STUN_AGENT_USAGE_IGNORE_CREDENTIALS);
1440 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
1441 agent->compatibility == NICE_COMPATIBILITY_WLM2009) {
1442 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1443 STUN_COMPATIBILITY_RFC3489,
1444 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS);
1445 } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
1446 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
1447 stun_agent_init (&cdisco->stun_agent, STUN_MSOC_KNOWN_ATTRIBUTES,
1448 STUN_COMPATIBILITY_OC2007,
1449 STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS |
1450 STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES);
1451 } else {
1452 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1453 STUN_COMPATIBILITY_RFC5389,
1454 STUN_AGENT_USAGE_ADD_SOFTWARE |
1455 STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS);
1457 stun_agent_set_software (&cdisco->stun_agent, agent->software_attribute);
1459 nice_debug ("Agent %p : Adding new relay-rflx candidate discovery %p\n",
1460 agent, cdisco);
1461 agent->discovery_list = g_slist_append (agent->discovery_list, cdisco);
1462 ++agent->discovery_unsched_items;
1465 NICEAPI_EXPORT guint
1466 nice_agent_add_stream (
1467 NiceAgent *agent,
1468 guint n_components)
1470 Stream *stream;
1471 guint ret = 0;
1472 guint i;
1474 agent_lock();
1475 stream = stream_new (n_components);
1477 agent->streams = g_slist_append (agent->streams, stream);
1478 stream->id = agent->next_stream_id++;
1479 nice_debug ("Agent %p : allocating stream id %u (%p)", agent, stream->id, stream);
1480 if (agent->reliable) {
1481 nice_debug ("Agent %p : reliable stream", agent);
1482 for (i = 0; i < n_components; i++) {
1483 Component *component = stream_find_component_by_id (stream, i + 1);
1484 if (component) {
1485 TcpUserData *data = g_slice_new0 (TcpUserData);
1486 PseudoTcpCallbacks tcp_callbacks = {data,
1487 pseudo_tcp_socket_opened,
1488 pseudo_tcp_socket_readable,
1489 pseudo_tcp_socket_writable,
1490 pseudo_tcp_socket_closed,
1491 pseudo_tcp_socket_write_packet};
1492 data->agent = agent;
1493 data->stream = stream;
1494 data->component = component;
1495 component->tcp_data = data;
1496 component->tcp = pseudo_tcp_socket_new (0, &tcp_callbacks);
1497 adjust_tcp_clock (agent, stream, component);
1498 nice_debug ("Agent %p: Create Pseudo Tcp Socket for component %d",
1499 agent, i+1);
1500 } else {
1501 nice_debug ("Agent %p: couldn't find component %d", agent, i+1);
1506 stream_initialize_credentials (stream, agent->rng);
1508 ret = stream->id;
1510 agent_unlock();
1511 return ret;
1515 NICEAPI_EXPORT gboolean
1516 nice_agent_set_relay_info(NiceAgent *agent,
1517 guint stream_id, guint component_id,
1518 const gchar *server_ip, guint server_port,
1519 const gchar *username, const gchar *password,
1520 NiceRelayType type)
1523 Component *component = NULL;
1525 g_return_val_if_fail (server_ip, FALSE);
1526 g_return_val_if_fail (server_port, FALSE);
1527 g_return_val_if_fail (username, FALSE);
1528 g_return_val_if_fail (password, FALSE);
1529 g_return_val_if_fail (type <= NICE_RELAY_TYPE_TURN_TLS, FALSE);
1531 agent_lock();
1533 if (agent_find_component (agent, stream_id, component_id, NULL, &component)) {
1534 TurnServer *turn = g_slice_new0 (TurnServer);
1535 nice_address_init (&turn->server);
1537 if (nice_address_set_from_string (&turn->server, server_ip)) {
1538 nice_address_set_port (&turn->server, server_port);
1539 } else {
1540 g_slice_free (TurnServer, turn);
1541 agent_unlock();
1542 return FALSE;
1546 turn->username = g_strdup (username);
1547 turn->password = g_strdup (password);
1548 turn->type = type;
1550 nice_debug ("Agent %p: added relay server [%s]:%d of type %d", agent,
1551 server_ip, server_port, type);
1553 component->turn_servers = g_list_append (component->turn_servers, turn);
1556 agent_unlock();
1557 return TRUE;
1560 #ifdef HAVE_GUPNP
1562 static gboolean priv_upnp_timeout_cb (gpointer user_data)
1564 NiceAgent *agent = (NiceAgent*)user_data;
1565 GSList *i;
1567 agent_lock();
1569 if (g_source_is_destroyed (g_main_current_source ())) {
1570 agent_unlock ();
1571 return FALSE;
1574 nice_debug ("Agent %p : UPnP port mapping timed out", agent);
1576 for (i = agent->upnp_mapping; i; i = i->next) {
1577 NiceAddress *a = i->data;
1578 nice_address_free (a);
1580 g_slist_free (agent->upnp_mapping);
1581 agent->upnp_mapping = NULL;
1583 if (agent->upnp_timer_source != NULL) {
1584 g_source_destroy (agent->upnp_timer_source);
1585 g_source_unref (agent->upnp_timer_source);
1586 agent->upnp_timer_source = NULL;
1589 agent_gathering_done (agent);
1591 agent_unlock();
1592 return FALSE;
1595 static void _upnp_mapped_external_port (GUPnPSimpleIgd *self, gchar *proto,
1596 gchar *external_ip, gchar *replaces_external_ip, guint external_port,
1597 gchar *local_ip, guint local_port, gchar *description, gpointer user_data)
1599 NiceAgent *agent = (NiceAgent*)user_data;
1600 NiceAddress localaddr;
1601 NiceAddress externaddr;
1603 GSList *i, *j, *k;
1605 agent_lock();
1607 nice_debug ("Agent %p : Successfully mapped %s:%d to %s:%d", agent, local_ip,
1608 local_port, external_ip, external_port);
1610 if (!nice_address_set_from_string (&localaddr, local_ip))
1611 goto end;
1612 nice_address_set_port (&localaddr, local_port);
1614 for (i = agent->upnp_mapping; i; i = i->next) {
1615 NiceAddress *addr = i->data;
1616 if (nice_address_equal (&localaddr, addr)) {
1617 agent->upnp_mapping = g_slist_remove (agent->upnp_mapping, addr);
1618 nice_address_free (addr);
1619 break;
1623 if (!nice_address_set_from_string (&externaddr, external_ip))
1624 goto end;
1625 nice_address_set_port (&externaddr, external_port);
1627 for (i = agent->streams; i; i = i->next) {
1628 Stream *stream = i->data;
1629 for (j = stream->components; j; j = j->next) {
1630 Component *component = j->data;
1631 for (k = component->local_candidates; k; k = k->next) {
1632 NiceCandidate *local_candidate = k->data;
1634 if (nice_address_equal (&localaddr, &local_candidate->base_addr)) {
1635 discovery_add_server_reflexive_candidate (
1636 agent,
1637 stream->id,
1638 component->id,
1639 &externaddr,
1640 local_candidate->sockptr);
1641 goto end;
1647 end:
1648 if (g_slist_length (agent->upnp_mapping)) {
1649 if (agent->upnp_timer_source != NULL) {
1650 g_source_destroy (agent->upnp_timer_source);
1651 g_source_unref (agent->upnp_timer_source);
1652 agent->upnp_timer_source = NULL;
1654 agent_gathering_done (agent);
1657 agent_unlock();
1660 static void _upnp_error_mapping_port (GUPnPSimpleIgd *self, GError *error,
1661 gchar *proto, guint external_port, gchar *local_ip, guint local_port,
1662 gchar *description, gpointer user_data)
1664 NiceAgent *agent = (NiceAgent*)user_data;
1665 NiceAddress localaddr;
1666 GSList *i;
1668 agent_lock();
1670 nice_debug ("Agent %p : Error mapping %s:%d to %d (%d) : %s", agent, local_ip,
1671 local_port, external_port, error->domain, error->message);
1672 if (nice_address_set_from_string (&localaddr, local_ip)) {
1673 nice_address_set_port (&localaddr, local_port);
1675 for (i = agent->upnp_mapping; i; i = i->next) {
1676 NiceAddress *addr = i->data;
1677 if (nice_address_equal (&localaddr, addr)) {
1678 agent->upnp_mapping = g_slist_remove (agent->upnp_mapping, addr);
1679 nice_address_free (addr);
1680 break;
1684 if (g_slist_length (agent->upnp_mapping)) {
1685 if (agent->upnp_timer_source != NULL) {
1686 g_source_destroy (agent->upnp_timer_source);
1687 g_source_unref (agent->upnp_timer_source);
1688 agent->upnp_timer_source = NULL;
1690 agent_gathering_done (agent);
1694 agent_unlock();
1697 #endif
1699 NICEAPI_EXPORT gboolean
1700 nice_agent_gather_candidates (
1701 NiceAgent *agent,
1702 guint stream_id)
1704 guint n;
1705 GSList *i;
1706 Stream *stream;
1707 GSList *local_addresses = NULL;
1708 gboolean ret = TRUE;
1710 agent_lock();
1712 stream = agent_find_stream (agent, stream_id);
1713 if (stream == NULL) {
1714 agent_unlock();
1715 return FALSE;
1718 nice_debug ("Agent %p : In %s mode, starting candidate gathering.", agent,
1719 agent->full_mode ? "ICE-FULL" : "ICE-LITE");
1721 #ifdef HAVE_GUPNP
1722 priv_free_upnp (agent);
1724 if (agent->upnp_enabled) {
1725 agent->upnp = gupnp_simple_igd_thread_new ();
1727 agent->upnp_timer_source = agent_timeout_add_with_context (agent,
1728 agent->upnp_timeout, priv_upnp_timeout_cb, agent);
1730 if (agent->upnp) {
1731 g_signal_connect (agent->upnp, "mapped-external-port",
1732 G_CALLBACK (_upnp_mapped_external_port), agent);
1733 g_signal_connect (agent->upnp, "error-mapping-port",
1734 G_CALLBACK (_upnp_error_mapping_port), agent);
1735 } else {
1736 nice_debug ("Agent %p : Error creating UPnP Simple IGD agent", agent);
1738 } else {
1739 nice_debug ("Agent %p : UPnP property Disabled", agent);
1741 #else
1742 nice_debug ("Agent %p : libnice compiled without UPnP support", agent);
1743 #endif
1745 /* if no local addresses added, generate them ourselves */
1746 if (agent->local_addresses == NULL) {
1747 GList *addresses = nice_interfaces_get_local_ips (FALSE);
1748 GList *item;
1750 for (item = addresses; item; item = g_list_next (item)) {
1751 NiceAddress *addr = nice_address_new ();
1753 if (nice_address_set_from_string (addr, item->data)) {
1754 local_addresses = g_slist_append (local_addresses, addr);
1755 } else {
1756 nice_address_free (addr);
1760 g_list_foreach (addresses, (GFunc) g_free, NULL);
1761 g_list_free (addresses);
1762 } else {
1763 for (i = agent->local_addresses; i; i = i->next) {
1764 NiceAddress *addr = i->data;
1765 NiceAddress *dup = nice_address_dup (addr);
1767 local_addresses = g_slist_append (local_addresses, dup);
1771 /* generate a local host candidate for each local address */
1772 for (i = local_addresses; i; i = i->next) {
1773 NiceAddress *addr = i->data;
1774 NiceCandidate *host_candidate;
1776 #ifdef HAVE_GUPNP
1777 gchar local_ip[NICE_ADDRESS_STRING_LEN];
1778 nice_address_to_string (addr, local_ip);
1779 #endif
1781 for (n = 0; n < stream->n_components; n++) {
1782 Component *component = stream_find_component_by_id (stream, n + 1);
1783 guint current_port = component->min_port;
1785 if (agent->reliable && component->tcp == NULL) {
1786 nice_debug ("Agent %p: not gathering candidates for s%d:%d because "
1787 "pseudo tcp socket does not exist in reliable mode", agent,
1788 stream->id, component->id);
1789 continue;
1792 host_candidate = NULL;
1793 while (host_candidate == NULL) {
1794 nice_debug ("Agent %p: Trying to create host candidate on port %d", agent, current_port);
1795 nice_address_set_port (addr, current_port);
1796 host_candidate = discovery_add_local_host_candidate (agent, stream->id,
1797 n + 1, addr);
1798 if (current_port > 0)
1799 current_port++;
1800 if (current_port == 0 || current_port > component->max_port)
1801 break;
1803 nice_address_set_port (addr, 0);
1805 if (!host_candidate) {
1806 gchar ip[NICE_ADDRESS_STRING_LEN];
1807 nice_address_to_string (addr, ip);
1808 nice_debug ("Agent %p: Unable to add local host candidate %s for s%d:%d"
1809 ". Invalid interface?", agent, ip, stream->id, component->id);
1810 ret = FALSE;
1811 goto error;
1814 #ifdef HAVE_GUPNP
1815 if (agent->upnp_enabled) {
1816 NiceAddress *addr = nice_address_dup (&host_candidate->base_addr);
1817 nice_debug ("Agent %p: Adding UPnP port %s:%d", agent, local_ip,
1818 nice_address_get_port (&host_candidate->base_addr));
1819 gupnp_simple_igd_add_port (GUPNP_SIMPLE_IGD (agent->upnp), "UDP",
1820 0, local_ip, nice_address_get_port (&host_candidate->base_addr),
1821 0, PACKAGE_STRING);
1822 agent->upnp_mapping = g_slist_prepend (agent->upnp_mapping, addr);
1824 #endif
1826 if (agent->full_mode &&
1827 agent->stun_server_ip) {
1828 NiceAddress stun_server;
1829 if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
1830 nice_address_set_port (&stun_server, agent->stun_server_port);
1832 priv_add_new_candidate_discovery_stun (agent,
1833 host_candidate->sockptr,
1834 stun_server,
1835 stream,
1836 n + 1);
1840 if (agent->full_mode && component) {
1841 GList *item;
1843 for (item = component->turn_servers; item; item = item->next) {
1844 TurnServer *turn = item->data;
1846 priv_add_new_candidate_discovery_turn (agent,
1847 host_candidate->sockptr,
1848 turn,
1849 stream,
1850 n + 1);
1856 stream->gathering = TRUE;
1859 /* Only signal the new candidates after we're sure that the gathering was
1860 * succesfful. But before sending gathering-done */
1861 for (n = 0; n < stream->n_components; n++) {
1862 Component *component = stream_find_component_by_id (stream, n + 1);
1863 for (i = component->local_candidates; i; i = i->next) {
1864 NiceCandidate *candidate = i->data;
1865 agent_signal_new_candidate (agent, candidate);
1869 /* note: no async discoveries pending, signal that we are ready */
1870 if (agent->discovery_unsched_items == 0) {
1871 nice_debug ("Agent %p: Candidate gathering FINISHED, no scheduled items.",
1872 agent);
1873 agent_gathering_done (agent);
1874 } else {
1875 g_assert (agent->discovery_list);
1876 discovery_schedule (agent);
1879 error:
1880 for (i = local_addresses; i; i = i->next)
1881 nice_address_free (i->data);
1882 g_slist_free (local_addresses);
1884 if (ret == FALSE) {
1885 priv_free_upnp (agent);
1886 for (n = 0; n < stream->n_components; n++) {
1887 Component *component = stream_find_component_by_id (stream, n + 1);
1889 priv_detach_stream_component (stream, component);
1891 for (i = component->local_candidates; i; i = i->next) {
1892 NiceCandidate *candidate = i->data;
1893 nice_candidate_free (candidate);
1895 for (i = component->sockets; i; i = i->next) {
1896 NiceSocket *udpsocket = i->data;
1897 nice_socket_free (udpsocket);
1899 g_slist_free (component->local_candidates);
1900 component->local_candidates = NULL;
1901 g_slist_free (component->sockets);
1902 component->sockets = NULL;
1904 discovery_prune_stream (agent, stream_id);
1907 agent_unlock();
1909 return ret;
1912 static void priv_free_upnp (NiceAgent *agent)
1914 #ifdef HAVE_GUPNP
1915 GSList *i;
1917 if (agent->upnp) {
1918 g_object_unref (agent->upnp);
1919 agent->upnp = NULL;
1922 for (i = agent->upnp_mapping; i; i = i->next) {
1923 NiceAddress *a = i->data;
1924 nice_address_free (a);
1926 g_slist_free (agent->upnp_mapping);
1927 agent->upnp_mapping = NULL;
1929 if (agent->upnp_timer_source != NULL) {
1930 g_source_destroy (agent->upnp_timer_source);
1931 g_source_unref (agent->upnp_timer_source);
1932 agent->upnp_timer_source = NULL;
1934 #endif
1937 static void priv_remove_keepalive_timer (NiceAgent *agent)
1939 if (agent->keepalive_timer_source != NULL) {
1940 g_source_destroy (agent->keepalive_timer_source);
1941 g_source_unref (agent->keepalive_timer_source);
1942 agent->keepalive_timer_source = NULL;
1946 NICEAPI_EXPORT void
1947 nice_agent_remove_stream (
1948 NiceAgent *agent,
1949 guint stream_id)
1951 /* note that streams/candidates can be in use by other threads */
1953 Stream *stream;
1955 agent_lock();
1956 stream = agent_find_stream (agent, stream_id);
1958 if (!stream) {
1959 goto done;
1962 /* note: remove items with matching stream_ids from both lists */
1963 conn_check_prune_stream (agent, stream);
1964 discovery_prune_stream (agent, stream_id);
1965 refresh_prune_stream (agent, stream_id);
1967 /* remove the stream itself */
1968 agent->streams = g_slist_remove (agent->streams, stream);
1969 stream_free (stream);
1971 if (!agent->streams)
1972 priv_remove_keepalive_timer (agent);
1974 done:
1975 agent_unlock();
1978 NICEAPI_EXPORT void
1979 nice_agent_set_port_range (NiceAgent *agent, guint stream_id, guint component_id,
1980 guint min_port, guint max_port)
1982 Component *component;
1984 agent_lock();
1986 if (agent_find_component (agent, stream_id, component_id, NULL, &component)) {
1987 component->min_port = min_port;
1988 component->max_port = max_port;
1991 agent_unlock();
1994 NICEAPI_EXPORT gboolean
1995 nice_agent_add_local_address (NiceAgent *agent, NiceAddress *addr)
1997 NiceAddress *dup;
1999 agent_lock();
2001 dup = nice_address_dup (addr);
2002 nice_address_set_port (dup, 0);
2003 agent->local_addresses = g_slist_append (agent->local_addresses, dup);
2005 agent_unlock();
2006 return TRUE;
2009 static gboolean priv_add_remote_candidate (
2010 NiceAgent *agent,
2011 guint stream_id,
2012 guint component_id,
2013 NiceCandidateType type,
2014 const NiceAddress *addr,
2015 const NiceAddress *base_addr,
2016 NiceCandidateTransport transport,
2017 guint32 priority,
2018 const gchar *username,
2019 const gchar *password,
2020 const gchar *foundation)
2022 Component *component;
2023 NiceCandidate *candidate;
2025 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
2026 return FALSE;
2028 /* step: check whether the candidate already exists */
2029 candidate = component_find_remote_candidate(component, addr, transport);
2030 if (candidate) {
2032 gchar tmpbuf[INET6_ADDRSTRLEN];
2033 nice_address_to_string (addr, tmpbuf);
2034 nice_debug ("Agent %p : Updating existing remote candidate with addr [%s]:%u"
2035 " for s%d/c%d. U/P '%s'/'%s' prio: %u", agent, tmpbuf,
2036 nice_address_get_port (addr), stream_id, component_id,
2037 username, password, priority);
2039 /* case 1: an existing candidate, update the attributes */
2040 candidate->type = type;
2041 if (base_addr)
2042 candidate->base_addr = *base_addr;
2043 candidate->priority = priority;
2044 if (foundation)
2045 g_strlcpy(candidate->foundation, foundation,
2046 NICE_CANDIDATE_MAX_FOUNDATION);
2047 /* note: username and password must remain the same during
2048 * a session; see sect 9.1.2 in ICE ID-19 */
2050 /* note: however, the user/pass in ID-19 is global, if the user/pass
2051 * are set in the candidate here, it means they need to be updated...
2052 * this is essential to overcome a race condition where we might receive
2053 * a valid binding request from a valid candidate that wasn't yet added to
2054 * our list of candidates.. this 'update' will make the peer-rflx a
2055 * server-rflx/host candidate again and restore that user/pass it needed
2056 * to have in the first place */
2057 if (username) {
2058 g_free (candidate->username);
2059 candidate->username = g_strdup (username);
2061 if (password) {
2062 g_free (candidate->password);
2063 candidate->password = g_strdup (password);
2065 if (conn_check_add_for_candidate (agent, stream_id, component, candidate) < 0)
2066 goto errors;
2068 else {
2069 /* case 2: add a new candidate */
2071 candidate = nice_candidate_new (type);
2072 component->remote_candidates = g_slist_append (component->remote_candidates,
2073 candidate);
2075 candidate->stream_id = stream_id;
2076 candidate->component_id = component_id;
2078 candidate->type = type;
2079 if (addr)
2080 candidate->addr = *addr;
2083 gchar tmpbuf[INET6_ADDRSTRLEN] = {0};
2084 if(addr)
2085 nice_address_to_string (addr, tmpbuf);
2086 nice_debug ("Agent %p : Adding remote candidate with addr [%s]:%u"
2087 " for s%d/c%d. U/P '%s'/'%s' prio: %u", agent, tmpbuf,
2088 addr? nice_address_get_port (addr) : 0, stream_id, component_id,
2089 username, password, priority);
2092 if (base_addr)
2093 candidate->base_addr = *base_addr;
2095 candidate->transport = transport;
2096 candidate->priority = priority;
2097 candidate->username = g_strdup (username);
2098 candidate->password = g_strdup (password);
2100 if (foundation)
2101 g_strlcpy (candidate->foundation, foundation,
2102 NICE_CANDIDATE_MAX_FOUNDATION);
2104 if (conn_check_add_for_candidate (agent, stream_id, component, candidate) < 0)
2105 goto errors;
2108 return TRUE;
2110 errors:
2111 nice_candidate_free (candidate);
2112 return FALSE;
2115 NICEAPI_EXPORT gboolean
2116 nice_agent_set_remote_credentials (
2117 NiceAgent *agent,
2118 guint stream_id,
2119 const gchar *ufrag, const gchar *pwd)
2121 Stream *stream;
2122 gboolean ret = FALSE;
2124 agent_lock();
2126 stream = agent_find_stream (agent, stream_id);
2127 /* note: oddly enough, ufrag and pwd can be empty strings */
2128 if (stream && ufrag && pwd) {
2130 g_strlcpy (stream->remote_ufrag, ufrag, NICE_STREAM_MAX_UFRAG);
2131 g_strlcpy (stream->remote_password, pwd, NICE_STREAM_MAX_PWD);
2133 ret = TRUE;
2134 goto done;
2137 done:
2138 agent_unlock();
2139 return ret;
2143 NICEAPI_EXPORT gboolean
2144 nice_agent_get_local_credentials (
2145 NiceAgent *agent,
2146 guint stream_id,
2147 gchar **ufrag, gchar **pwd)
2149 Stream *stream;
2150 gboolean ret = TRUE;
2152 agent_lock();
2154 stream = agent_find_stream (agent, stream_id);
2155 if (stream == NULL) {
2156 goto done;
2159 if (!ufrag || !pwd) {
2160 goto done;
2163 *ufrag = g_strdup (stream->local_ufrag);
2164 *pwd = g_strdup (stream->local_password);
2165 ret = TRUE;
2167 done:
2169 agent_unlock();
2170 return ret;
2173 NICEAPI_EXPORT int
2174 nice_agent_set_remote_candidates (NiceAgent *agent, guint stream_id, guint component_id, const GSList *candidates)
2176 const GSList *i;
2177 int added = 0;
2178 Stream *stream;
2179 Component *component;
2181 nice_debug ("Agent %p: set_remote_candidates %d %d", agent, stream_id, component_id);
2183 agent_lock();
2185 if (!agent_find_component (agent, stream_id, component_id,
2186 &stream, &component)) {
2187 g_warning ("Could not find component %u in stream %u", component_id,
2188 stream_id);
2189 added = -1;
2190 goto done;
2193 if (agent->discovery_unsched_items > 0 || stream->gathering) {
2194 nice_debug ("Agent %p: Remote candidates refused for stream %d because "
2195 "we are still gathering our own candidates", agent, stream_id);
2196 added = -1;
2197 goto done;
2200 if (agent->reliable && component->tcp == NULL) {
2201 nice_debug ("Agent %p: not setting remote candidate for s%d:%d because "
2202 "pseudo tcp socket does not exist in reliable mode", agent,
2203 stream->id, component->id);
2204 goto done;
2207 for (i = candidates; i && added >= 0; i = i->next) {
2208 NiceCandidate *d = (NiceCandidate*) i->data;
2210 if (nice_address_is_valid (&d->addr) == TRUE) {
2211 gboolean res =
2212 priv_add_remote_candidate (agent,
2213 stream_id,
2214 component_id,
2215 d->type,
2216 &d->addr,
2217 &d->base_addr,
2218 d->transport,
2219 d->priority,
2220 d->username,
2221 d->password,
2222 d->foundation);
2223 if (res)
2224 ++added;
2228 conn_check_remote_candidates_set(agent);
2230 if (added > 0) {
2231 gboolean res = conn_check_schedule_next (agent);
2232 if (res != TRUE)
2233 nice_debug ("Agent %p : Warning: unable to schedule any conn checks!", agent);
2236 done:
2237 agent_unlock();
2238 return added;
2242 static gint
2243 _nice_agent_recv (
2244 NiceAgent *agent,
2245 Stream *stream,
2246 Component *component,
2247 NiceSocket *socket,
2248 guint buf_len,
2249 gchar *buf)
2251 NiceAddress from;
2252 gint len;
2253 GList *item;
2255 len = nice_socket_recv (socket, &from, buf_len, buf);
2257 if (len <= 0)
2258 return len;
2260 #ifndef NDEBUG
2261 if (len > 0) {
2262 gchar tmpbuf[INET6_ADDRSTRLEN];
2263 nice_address_to_string (&from, tmpbuf);
2264 nice_debug ("Agent %p : Packet received on local socket %u from [%s]:%u (%u octets).", agent,
2265 socket->fileno, tmpbuf, nice_address_get_port (&from), len);
2267 #endif
2270 if ((guint)len > buf_len)
2272 /* buffer is not big enough to accept this packet */
2273 /* XXX: test this case */
2274 return 0;
2277 for (item = component->turn_servers; item; item = g_list_next (item)) {
2278 TurnServer *turn = item->data;
2279 if (nice_address_equal (&from, &turn->server)) {
2280 GSList * i = NULL;
2281 #ifndef NDEBUG
2282 nice_debug ("Agent %p : Packet received from TURN server candidate.",
2283 agent);
2284 #endif
2285 for (i = component->local_candidates; i; i = i->next) {
2286 NiceCandidate *cand = i->data;
2287 if (cand->type == NICE_CANDIDATE_TYPE_RELAYED &&
2288 cand->stream_id == stream->id &&
2289 cand->component_id == component->id) {
2290 len = nice_turn_socket_parse_recv (cand->sockptr, &socket,
2291 &from, len, buf, &from, buf, len);
2294 break;
2298 agent->media_after_tick = TRUE;
2300 if (stun_message_validate_buffer_length ((uint8_t *) buf, (size_t) len,
2301 (agent->compatibility != NICE_COMPATIBILITY_OC2007 &&
2302 agent->compatibility != NICE_COMPATIBILITY_OC2007R2)) != len)
2303 /* If the retval is no 0, its not a valid stun packet, probably data */
2304 return len;
2307 if (conn_check_handle_inbound_stun (agent, stream, component, socket,
2308 &from, buf, len))
2309 /* handled STUN message*/
2310 return 0;
2312 /* unhandled STUN, pass to client */
2313 return len;
2317 NICEAPI_EXPORT gint
2318 nice_agent_send (
2319 NiceAgent *agent,
2320 guint stream_id,
2321 guint component_id,
2322 guint len,
2323 const gchar *buf)
2325 Stream *stream;
2326 Component *component;
2327 gint ret = -1;
2329 agent_lock();
2331 if (!agent_find_component (agent, stream_id, component_id,
2332 &stream, &component)) {
2333 goto done;
2336 if (component->tcp != NULL) {
2337 ret = pseudo_tcp_socket_send (component->tcp, buf, len);
2338 adjust_tcp_clock (agent, stream, component);
2340 if (ret == -1 &&
2341 pseudo_tcp_socket_get_error (component->tcp) != EWOULDBLOCK) {
2344 /* In case of -1, the error is either EWOULDBLOCK or ENOTCONN, which both
2345 need the user to wait for the reliable-transport-writable signal */
2346 } else if(agent->reliable) {
2347 nice_debug ("Trying to send on a pseudo tcp FAILED component");
2348 goto done;
2349 } else if (component->selected_pair.local != NULL) {
2350 NiceSocket *sock;
2351 NiceAddress *addr;
2353 #ifndef NDEBUG
2354 gchar tmpbuf[INET6_ADDRSTRLEN];
2355 nice_address_to_string (&component->selected_pair.remote->addr, tmpbuf);
2357 nice_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", agent, stream_id, component_id,
2358 len, tmpbuf,
2359 nice_address_get_port (&component->selected_pair.remote->addr));
2360 #endif
2362 sock = component->selected_pair.local->sockptr;
2363 addr = &component->selected_pair.remote->addr;
2364 if (nice_socket_send (sock, addr, len, buf)) {
2365 ret = len;
2367 goto done;
2370 done:
2371 agent_unlock();
2372 return ret;
2376 NICEAPI_EXPORT GSList *
2377 nice_agent_get_local_candidates (
2378 NiceAgent *agent,
2379 guint stream_id,
2380 guint component_id)
2382 Component *component;
2383 GSList * ret = NULL;
2384 GSList * item = NULL;
2386 agent_lock();
2388 if (!agent_find_component (agent, stream_id, component_id, NULL, &component)) {
2389 goto done;
2392 for (item = component->local_candidates; item; item = item->next)
2393 ret = g_slist_append (ret, nice_candidate_copy (item->data));
2395 done:
2396 agent_unlock();
2397 return ret;
2401 NICEAPI_EXPORT GSList *
2402 nice_agent_get_remote_candidates (
2403 NiceAgent *agent,
2404 guint stream_id,
2405 guint component_id)
2407 Component *component;
2408 GSList *ret = NULL, *item = NULL;
2410 agent_lock();
2411 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
2413 goto done;
2416 for (item = component->remote_candidates; item; item = item->next)
2417 ret = g_slist_append (ret, nice_candidate_copy (item->data));
2419 done:
2420 agent_unlock();
2421 return ret;
2425 gboolean
2426 nice_agent_restart (
2427 NiceAgent *agent)
2429 GSList *i;
2430 gboolean res = TRUE;
2432 agent_lock();
2434 /* step: clean up all connectivity checks */
2435 conn_check_free (agent);
2437 /* step: regenerate tie-breaker value */
2438 priv_generate_tie_breaker (agent);
2440 for (i = agent->streams; i && res; i = i->next) {
2441 Stream *stream = i->data;
2443 /* step: reset local credentials for the stream and
2444 * clean up the list of remote candidates */
2445 res = stream_restart (stream, agent->rng);
2448 agent_unlock();
2449 return res;
2453 static void
2454 nice_agent_dispose (GObject *object)
2456 GSList *i;
2457 NiceAgent *agent = NICE_AGENT (object);
2459 /* step: free resources for the binding discovery timers */
2460 discovery_free (agent);
2461 g_assert (agent->discovery_list == NULL);
2462 refresh_free (agent);
2463 g_assert (agent->refresh_list == NULL);
2465 /* step: free resources for the connectivity check timers */
2466 conn_check_free (agent);
2468 priv_remove_keepalive_timer (agent);
2470 for (i = agent->local_addresses; i; i = i->next)
2472 NiceAddress *a = i->data;
2474 nice_address_free (a);
2477 g_slist_free (agent->local_addresses);
2478 agent->local_addresses = NULL;
2480 for (i = agent->streams; i; i = i->next)
2482 Stream *s = i->data;
2484 stream_free (s);
2487 g_slist_free (agent->streams);
2488 agent->streams = NULL;
2490 g_free (agent->stun_server_ip);
2491 agent->stun_server_ip = NULL;
2493 g_free (agent->proxy_ip);
2494 agent->proxy_ip = NULL;
2495 g_free (agent->proxy_username);
2496 agent->proxy_username = NULL;
2497 g_free (agent->proxy_password);
2498 agent->proxy_password = NULL;
2500 nice_rng_free (agent->rng);
2501 agent->rng = NULL;
2503 priv_free_upnp (agent);
2505 g_free (agent->software_attribute);
2506 agent->software_attribute = NULL;
2508 if (agent->main_context != NULL)
2509 g_main_context_unref (agent->main_context);
2510 agent->main_context = NULL;
2512 if (G_OBJECT_CLASS (nice_agent_parent_class)->dispose)
2513 G_OBJECT_CLASS (nice_agent_parent_class)->dispose (object);
2518 typedef struct _IOCtx IOCtx;
2520 struct _IOCtx
2522 GIOChannel *channel;
2523 GSource *source;
2524 NiceAgent *agent;
2525 Stream *stream;
2526 Component *component;
2527 NiceSocket *socket;
2531 static IOCtx *
2532 io_ctx_new (
2533 NiceAgent *agent,
2534 Stream *stream,
2535 Component *component,
2536 NiceSocket *socket,
2537 GIOChannel *channel,
2538 GSource *source)
2540 IOCtx *ctx;
2542 ctx = g_slice_new0 (IOCtx);
2543 ctx->agent = agent;
2544 ctx->stream = stream;
2545 ctx->component = component;
2546 ctx->socket = socket;
2547 ctx->channel = channel;
2548 ctx->source = source;
2550 return ctx;
2554 static void
2555 io_ctx_free (IOCtx *ctx)
2557 g_io_channel_unref (ctx->channel);
2558 g_slice_free (IOCtx, ctx);
2561 static gboolean
2562 nice_agent_g_source_cb (
2563 GIOChannel *io,
2564 G_GNUC_UNUSED
2565 GIOCondition condition,
2566 gpointer data)
2568 /* return value is whether to keep the source */
2570 IOCtx *ctx = data;
2571 NiceAgent *agent = ctx->agent;
2572 Stream *stream = ctx->stream;
2573 Component *component = ctx->component;
2574 gchar buf[MAX_BUFFER_SIZE];
2575 gint len;
2577 agent_lock();
2579 if (g_source_is_destroyed (g_main_current_source ())) {
2580 agent_unlock ();
2581 return FALSE;
2584 /* note: dear compiler, these are for you: */
2585 (void)io;
2587 len = _nice_agent_recv (agent, stream, component, ctx->socket,
2588 MAX_BUFFER_SIZE, buf);
2590 if (len > 0 && component->tcp) {
2591 g_object_add_weak_pointer (G_OBJECT (agent), (gpointer *)&agent);
2592 pseudo_tcp_socket_notify_packet (component->tcp, buf, len);
2593 if (agent) {
2594 adjust_tcp_clock (agent, stream, component);
2595 g_object_remove_weak_pointer (G_OBJECT (agent), (gpointer *)&agent);
2596 } else {
2597 nice_debug ("Our agent got destroyed in notify_packet!!");
2599 } else if(len > 0 && agent->reliable) {
2600 nice_debug ("Received data on a pseudo tcp FAILED component");
2601 } else if (len > 0 && component->g_source_io_cb) {
2602 gpointer data = component->data;
2603 gint sid = stream->id;
2604 gint cid = component->id;
2605 NiceAgentRecvFunc callback = component->g_source_io_cb;
2606 /* Unlock the agent before calling the callback */
2607 agent_unlock();
2608 callback (agent, sid, cid, len, buf, data);
2609 goto done;
2610 } else if (len < 0) {
2611 GSource *source = ctx->source;
2613 nice_debug ("Agent %p: _nice_agent_recv returned %d, errno (%d) : %s",
2614 agent, len, errno, g_strerror (errno));
2615 component->gsources = g_slist_remove (component->gsources, source);
2616 g_source_destroy (source);
2617 g_source_unref (source);
2618 /* We don't close the socket because it would be way too complicated to
2619 * take care of every path where the socket might still be used.. */
2620 nice_debug ("Agent %p: unable to recv from socket %p. Detaching", agent,
2621 ctx->socket);
2625 agent_unlock();
2627 done:
2629 return TRUE;
2633 * Attaches one socket handle to the main loop event context
2636 void
2637 agent_attach_stream_component_socket (NiceAgent *agent,
2638 Stream *stream,
2639 Component *component,
2640 NiceSocket *socket)
2642 GIOChannel *io;
2643 GSource *source;
2644 IOCtx *ctx;
2646 if (!component->ctx)
2647 return;
2649 io = g_io_channel_unix_new (socket->fileno);
2650 /* note: without G_IO_ERR the glib mainloop goes into
2651 * busyloop if errors are encountered */
2652 source = g_io_create_watch (io, G_IO_IN | G_IO_ERR);
2653 ctx = io_ctx_new (agent, stream, component, socket, io, source);
2654 g_source_set_callback (source, (GSourceFunc) nice_agent_g_source_cb,
2655 ctx, (GDestroyNotify) io_ctx_free);
2656 nice_debug ("Agent %p : Attach source %p (stream %u).", agent, source, stream->id);
2657 g_source_attach (source, component->ctx);
2658 component->gsources = g_slist_append (component->gsources, source);
2663 * Attaches socket handles of 'stream' to the main eventloop
2664 * context.
2667 static gboolean
2668 priv_attach_stream_component (NiceAgent *agent,
2669 Stream *stream,
2670 Component *component)
2672 GSList *i;
2674 for (i = component->sockets; i; i = i->next)
2675 agent_attach_stream_component_socket (agent, stream, component, i->data);
2677 return TRUE;
2681 * Detaches socket handles of 'stream' from the main eventloop
2682 * context.
2685 static void priv_detach_stream_component (Stream *stream, Component *component)
2687 GSList *i;
2689 for (i = component->gsources; i; i = i->next) {
2690 GSource *source = i->data;
2691 nice_debug ("Detach source %p (stream %u).", source, stream->id);
2692 g_source_destroy (source);
2693 g_source_unref (source);
2696 g_slist_free (component->gsources);
2697 component->gsources = NULL;
2700 NICEAPI_EXPORT gboolean
2701 nice_agent_attach_recv (
2702 NiceAgent *agent,
2703 guint stream_id,
2704 guint component_id,
2705 GMainContext *ctx,
2706 NiceAgentRecvFunc func,
2707 gpointer data)
2709 Component *component = NULL;
2710 Stream *stream = NULL;
2711 gboolean ret = FALSE;
2713 agent_lock();
2715 /* attach candidates */
2717 /* step: check that params specify an existing pair */
2718 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
2719 g_warning ("Could not find component %u in stream %u", component_id,
2720 stream_id);
2721 goto done;
2724 if (component->g_source_io_cb)
2725 priv_detach_stream_component (stream, component);
2727 ret = TRUE;
2729 if (func) {
2730 component->g_source_io_cb = func;
2731 component->data = data;
2732 component->ctx = ctx;
2734 priv_attach_stream_component (agent, stream, component);
2736 /* If we got detached, maybe our readable callback didn't finish reading
2737 * all available data in the pseudotcp, so we need to make sure we free
2738 * our recv window, so the readable callback can be triggered again on the
2739 * next incoming data.
2740 * but only do this if we know we're already readable, otherwise we might
2741 * trigger an error in the initial, pre-connection attach. */
2742 if (component->tcp && component->tcp_data && component->tcp_readable)
2743 pseudo_tcp_socket_readable (component->tcp, component->tcp_data);
2745 } else {
2746 component->g_source_io_cb = NULL;
2747 component->data = NULL;
2748 component->ctx = NULL;
2752 done:
2753 agent_unlock();
2754 return ret;
2757 NICEAPI_EXPORT gboolean
2758 nice_agent_set_selected_pair (
2759 NiceAgent *agent,
2760 guint stream_id,
2761 guint component_id,
2762 const gchar *lfoundation,
2763 const gchar *rfoundation)
2765 Component *component;
2766 Stream *stream;
2767 CandidatePair pair;
2768 gboolean ret = FALSE;
2770 agent_lock();
2772 /* step: check that params specify an existing pair */
2773 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
2774 goto done;
2777 if (!component_find_pair (component, agent, lfoundation, rfoundation, &pair)){
2778 goto done;
2781 /* step: stop connectivity checks (note: for the whole stream) */
2782 conn_check_prune_stream (agent, stream);
2784 if (agent->reliable && component->tcp == NULL) {
2785 nice_debug ("Agent %p: not setting selected pair for s%d:%d because "
2786 "pseudo tcp socket does not exist in reliable mode", agent,
2787 stream->id, component->id);
2788 goto done;
2791 /* step: change component state */
2792 agent_signal_component_state_change (agent, stream_id, component_id, NICE_COMPONENT_STATE_READY);
2794 /* step: set the selected pair */
2795 component_update_selected_pair (component, &pair);
2796 agent_signal_new_selected_pair (agent, stream_id, component_id, lfoundation, rfoundation);
2798 ret = TRUE;
2800 done:
2801 agent_unlock();
2802 return ret;
2806 GSource* agent_timeout_add_with_context (NiceAgent *agent, guint interval,
2807 GSourceFunc function, gpointer data)
2809 GSource *source;
2810 guint id;
2812 g_return_val_if_fail (function != NULL, 0);
2814 source = g_timeout_source_new (interval);
2816 g_source_set_callback (source, function, data, NULL);
2817 id = g_source_attach (source, agent->main_context);
2819 return source;
2823 NICEAPI_EXPORT gboolean
2824 nice_agent_set_selected_remote_candidate (
2825 NiceAgent *agent,
2826 guint stream_id,
2827 guint component_id,
2828 NiceCandidate *candidate)
2830 Component *component;
2831 Stream *stream;
2832 NiceCandidate *lcandidate = NULL;
2833 gboolean ret = FALSE;
2835 agent_lock();
2837 /* step: check if the component exists*/
2838 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
2839 goto done;
2842 /* step: stop connectivity checks (note: for the whole stream) */
2843 conn_check_prune_stream (agent, stream);
2846 if (agent->reliable && component->tcp == NULL) {
2847 nice_debug ("Agent %p: not setting selected remote candidate s%d:%d because "
2848 "pseudo tcp socket does not exist in reliable mode", agent,
2849 stream->id, component->id);
2850 goto done;
2853 /* step: set the selected pair */
2854 lcandidate = component_set_selected_remote_candidate (agent, component,
2855 candidate);
2856 if (!lcandidate)
2857 goto done;
2859 /* step: change component state */
2860 agent_signal_component_state_change (agent, stream_id, component_id, NICE_COMPONENT_STATE_READY);
2862 agent_signal_new_selected_pair (agent, stream_id, component_id,
2863 lcandidate->foundation,
2864 candidate->foundation);
2866 ret = TRUE;
2868 done:
2869 agent_unlock();
2870 return ret;
2873 void
2874 _priv_set_socket_tos (NiceAgent *agent, NiceSocket *sock, gint tos)
2876 if (setsockopt (sock->fileno, IPPROTO_IP,
2877 IP_TOS, &tos, sizeof (tos)) < 0) {
2878 nice_debug ("Agent %p: Could not set socket ToS", agent,
2879 g_strerror (errno));
2881 #ifdef IPV6_TCLASS
2882 if (setsockopt (sock->fileno, IPPROTO_IPV6,
2883 IPV6_TCLASS, &tos, sizeof (tos)) < 0) {
2884 nice_debug ("Agent %p: Could not set IPV6 socket ToS", agent,
2885 g_strerror (errno));
2887 #endif
2891 void nice_agent_set_stream_tos (NiceAgent *agent,
2892 guint stream_id, gint tos)
2895 GSList *i, *j, *k;
2897 agent_lock();
2899 for (i = agent->streams; i; i = i->next) {
2900 Stream *stream = i->data;
2901 if (stream->id == stream_id) {
2902 stream->tos = tos;
2903 for (j = stream->components; j; j = j->next) {
2904 Component *component = j->data;
2906 for (k = component->local_candidates; k; k = k->next) {
2907 NiceCandidate *local_candidate = k->data;
2908 _priv_set_socket_tos (agent, local_candidate->sockptr, tos);
2914 agent_unlock();
2917 void nice_agent_set_software (NiceAgent *agent, const gchar *software)
2919 agent_lock();
2921 g_free (agent->software_attribute);
2922 if (software)
2923 agent->software_attribute = g_strdup_printf ("%s/%s",
2924 software, PACKAGE_STRING);
2926 stun_agent_set_software (&agent->stun_agent, agent->software_attribute);
2928 agent_unlock ();