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
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.
25 * Dafydd Harries, Collabora Ltd.
26 * Youness Alaoui, Collabora Ltd.
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.
44 #define NICEAPI_EXPORT
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
63 #include "stun/usages/turn.h"
64 #include "candidate.h"
65 #include "component.h"
66 #include "conncheck.h"
67 #include "discovery.h"
69 #include "agent-priv.h"
70 #include "agent-signals-marshal.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
);
90 PROP_COMPATIBILITY
= 1,
93 PROP_STUN_SERVER_PORT
,
94 PROP_CONTROLLING_MODE
,
96 PROP_STUN_PACING_TIMER
,
97 PROP_MAX_CONNECTIVITY_CHECKS
,
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
,
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
,
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
)
198 for (i
= agent
->streams
; i
; i
= i
->next
)
202 if (s
->id
== stream_id
)
211 agent_find_component (
216 Component
**component
)
221 s
= agent_find_stream (agent
, stream_id
);
226 c
= stream_find_component_by_id (s
, component_id
);
242 nice_agent_dispose (GObject
*object
);
245 nice_agent_get_property (
252 nice_agent_set_property (
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 (
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
,
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 (
301 "STUN server IP address",
302 "The IP address (not the hostname) of the STUN server to use",
306 g_object_class_install_property (gobject_class
, PROP_STUN_SERVER_PORT
,
310 "Port of the STUN server used to gather server-reflexive candidates",
312 1, /* not a construct property, ignored */
315 g_object_class_install_property (gobject_class
, PROP_CONTROLLING_MODE
,
316 g_param_spec_boolean (
318 "ICE controlling mode",
319 "Whether the agent is in controlling mode",
320 FALSE
, /* not a construct property, ignored */
323 g_object_class_install_property (gobject_class
, PROP_FULL_MODE
,
324 g_param_spec_boolean (
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
,
335 "Timer 'Ta' (msecs) used in the IETF ICE specification for pacing "
336 "candidate gathering and sending of connectivity checks",
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
,
344 "max-connectivity-checks",
345 "Maximum number of connectivity checks",
346 "Upper limit for the total number of connectivity checks performed",
348 0, /* default set in init */
352 * NiceAgent:proxy-ip:
354 * The proxy server IP used to bypass a proxy firewall
358 g_object_class_install_property (gobject_class
, PROP_PROXY_IP
,
359 g_param_spec_string (
362 "The proxy server IP used to bypass a proxy firewall",
367 * NiceAgent:proxy-port:
369 * The proxy server port used to bypass a proxy firewall
373 g_object_class_install_property (gobject_class
, PROP_PROXY_PORT
,
377 "The Proxy server port used to bypass a proxy firewall",
383 * NiceAgent:proxy-type:
385 * The type of proxy set in the proxy-ip property
389 g_object_class_install_property (gobject_class
, PROP_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
,
399 * NiceAgent:proxy-username:
401 * The username used to authenticate with the proxy
405 g_object_class_install_property (gobject_class
, PROP_PROXY_USERNAME
,
406 g_param_spec_string (
408 "Proxy server username",
409 "The username used to authenticate with the proxy",
414 * NiceAgent:proxy-password:
416 * The password used to authenticate with the proxy
420 g_object_class_install_property (gobject_class
, PROP_PROXY_PASSWORD
,
421 g_param_spec_string (
423 "Proxy server password",
424 "The password used to authenticate with the proxy",
431 * Whether the agent should use UPnP to open a port in the router and
432 * get the external IP
436 g_object_class_install_property (gobject_class
, PROP_UPNP
,
437 g_param_spec_boolean (
441 "Whether the agent should use UPnP to open a port in the router and "
442 "get the external IP",
444 "Use UPnP (disabled in build)",
445 "Does nothing because libnice was not built with UPnP support",
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
458 g_object_class_install_property (gobject_class
, PROP_UPNP_TIMEOUT
,
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",
466 "Timeout for UPnP discovery (disabled in build)",
467 "Does nothing because libnice was not built with UPnP support",
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
481 g_object_class_install_property (gobject_class
, PROP_RELIABLE
,
482 g_param_spec_boolean (
485 "Whether the agent should use PseudoTcp to ensure a reliable transport"
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
] =
503 "component-state-changed",
504 G_OBJECT_CLASS_TYPE (klass
),
509 agent_marshal_VOID__UINT_UINT_UINT
,
512 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_UINT
,
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
] =
525 "candidate-gathering-done",
526 G_OBJECT_CLASS_TYPE (klass
),
531 agent_marshal_VOID__UINT
,
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
] =
550 G_OBJECT_CLASS_TYPE (klass
),
555 agent_marshal_VOID__UINT_UINT_STRING_STRING
,
558 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_STRING
, G_TYPE_STRING
,
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
] =
574 G_OBJECT_CLASS_TYPE (klass
),
579 agent_marshal_VOID__UINT_UINT_STRING
,
582 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_STRING
,
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
] =
597 "new-remote-candidate",
598 G_OBJECT_CLASS_TYPE (klass
),
603 agent_marshal_VOID__UINT_UINT_STRING
,
606 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_STRING
,
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
617 signals
[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED
] =
619 "initial-binding-request-received",
620 G_OBJECT_CLASS_TYPE (klass
),
625 agent_marshal_VOID__UINT
,
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
645 signals
[SIGNAL_RELIABLE_TRANSPORT_WRITABLE
] =
647 "reliable-transport-writable",
648 G_OBJECT_CLASS_TYPE (klass
),
653 agent_marshal_VOID__UINT_UINT
,
656 G_TYPE_UINT
, G_TYPE_UINT
,
660 /* Init debug options depending on env variables */
664 static void priv_generate_tie_breaker (NiceAgent
*agent
)
666 nice_rng_generate_bytes (agent
->rng
, 8, (gchar
*)&agent
->tie_breaker
);
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
,
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
,
729 nice_agent_get_property (
735 NiceAgent
*agent
= NICE_AGENT (object
);
741 case PROP_MAIN_CONTEXT
:
742 g_value_set_pointer (value
, agent
->main_context
);
745 case PROP_COMPATIBILITY
:
746 g_value_set_uint (value
, agent
->compatibility
);
749 case PROP_STUN_SERVER
:
750 g_value_set_string (value
, agent
->stun_server_ip
);
753 case PROP_STUN_SERVER_PORT
:
754 g_value_set_uint (value
, agent
->stun_server_port
);
757 case PROP_CONTROLLING_MODE
:
758 g_value_set_boolean (value
, agent
->controlling_mode
);
762 g_value_set_boolean (value
, agent
->full_mode
);
765 case PROP_STUN_PACING_TIMER
:
766 g_value_set_uint (value
, agent
->timer_ta
);
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? */
775 g_value_set_string (value
, agent
->proxy_ip
);
778 case PROP_PROXY_PORT
:
779 g_value_set_uint (value
, agent
->proxy_port
);
782 case PROP_PROXY_TYPE
:
783 g_value_set_uint (value
, agent
->proxy_type
);
786 case PROP_PROXY_USERNAME
:
787 g_value_set_string (value
, agent
->proxy_username
);
790 case PROP_PROXY_PASSWORD
:
791 g_value_set_string (value
, agent
->proxy_password
);
796 g_value_set_boolean (value
, agent
->upnp_enabled
);
798 g_value_set_boolean (value
, FALSE
);
802 case PROP_UPNP_TIMEOUT
:
804 g_value_set_uint (value
, agent
->upnp_timeout
);
806 g_value_set_uint (value
, DEFAULT_UPNP_TIMEOUT
);
811 g_value_set_boolean (value
, agent
->reliable
);
815 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
823 nice_agent_set_property (
829 NiceAgent
*agent
= NICE_AGENT (object
);
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
);
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
);
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
);
880 case PROP_STUN_SERVER
:
881 g_free (agent
->stun_server_ip
);
882 agent
->stun_server_ip
= g_value_dup_string (value
);
885 case PROP_STUN_SERVER_PORT
:
886 agent
->stun_server_port
= g_value_get_uint (value
);
889 case PROP_CONTROLLING_MODE
:
890 agent
->controlling_mode
= g_value_get_boolean (value
);
894 agent
->full_mode
= g_value_get_boolean (value
);
897 case PROP_STUN_PACING_TIMER
:
898 agent
->timer_ta
= g_value_get_uint (value
);
901 case PROP_MAX_CONNECTIVITY_CHECKS
:
902 agent
->max_conn_checks
= g_value_get_uint (value
);
906 g_free (agent
->proxy_ip
);
907 agent
->proxy_ip
= g_value_dup_string (value
);
910 case PROP_PROXY_PORT
:
911 agent
->proxy_port
= g_value_get_uint (value
);
914 case PROP_PROXY_TYPE
:
915 agent
->proxy_type
= g_value_get_uint (value
);
918 case PROP_PROXY_USERNAME
:
919 g_free (agent
->proxy_username
);
920 agent
->proxy_username
= g_value_dup_string (value
);
923 case PROP_PROXY_PASSWORD
:
924 g_free (agent
->proxy_password
);
925 agent
->proxy_password
= g_value_dup_string (value
);
928 case PROP_UPNP_TIMEOUT
:
930 agent
->upnp_timeout
= g_value_get_uint (value
);
936 agent
->upnp_enabled
= g_value_get_boolean (value
);
941 agent
->reliable
= g_value_get_boolean (value
);
945 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
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
);
983 adjust_tcp_clock (NiceAgent
*agent
, Stream
*stream
, Component
*component
);
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
);
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
];
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
);
1019 if (component
->g_source_io_cb
)
1020 len
= pseudo_tcp_socket_recv (sock
, buf
, sizeof(buf
));
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 */
1031 callback (agent
, sid
, cid
, len
, buf
, data
);
1034 nice_debug ("PseudoTCP socket got destroyed in readable callback!");
1037 } else if (len
< 0 &&
1038 pseudo_tcp_socket_get_error (sock
) != EWOULDBLOCK
) {
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
;
1048 adjust_tcp_clock (agent
, stream
, component
);
1049 g_object_remove_weak_pointer (G_OBJECT (agent
), (gpointer
*)&agent
);
1051 nice_debug ("Not calling adjust_tcp_clock.. agent got destroyed!");
1054 g_object_remove_weak_pointer (G_OBJECT (sock
), (gpointer
*)&sock
);
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
);
1072 pseudo_tcp_socket_closed (PseudoTcpSocket
*sock
, guint32 err
,
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
) {
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
));
1106 sock
= component
->selected_pair
.local
->sockptr
;
1107 addr
= &component
->selected_pair
.remote
->addr
;
1108 if (nice_socket_send (sock
, addr
, len
, buffer
)) {
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
;
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");
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
);
1148 adjust_tcp_clock (NiceAgent
*agent
, Stream
*stream
, Component
*component
)
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
);
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
)
1200 conn_check_add_for_candidate (agent
, stream
->id
, component
, remote_candidate
);
1208 if (agent
->discovery_timer_source
== NULL
&&
1209 agent
->upnp_timer_source
== NULL
) {
1210 agent_signal_gathering_done (agent
);
1213 agent_signal_gathering_done (agent
);
1217 void agent_signal_gathering_done (NiceAgent
*agent
)
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
;
1245 if (!agent_find_component (agent
, stream_id
, component_id
,
1246 &stream
, &component
))
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");
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
);
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
;
1294 if (!agent_find_component (agent
, stream_id
, component_id
,
1295 &stream
, &component
))
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
);
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
);
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
);
1323 return nice_candidate_pair_priority (remote
->priority
, local
->priority
);
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",
1353 agent
->discovery_list
= g_slist_append (agent
->discovery_list
, cdisco
);
1354 ++agent
->discovery_unsched_items
;
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
);
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
;
1388 NiceAddress proxy_server
;
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
);
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
);
1406 nice_socket_free (socket
);
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
);
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",
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 (
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);
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",
1501 nice_debug ("Agent %p: couldn't find component %d", agent
, i
+1);
1506 stream_initialize_credentials (stream
, agent
->rng
);
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
,
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
);
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
);
1540 g_slice_free (TurnServer
, turn
);
1546 turn
->username
= g_strdup (username
);
1547 turn
->password
= g_strdup (password
);
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
);
1562 static gboolean
priv_upnp_timeout_cb (gpointer user_data
)
1564 NiceAgent
*agent
= (NiceAgent
*)user_data
;
1569 if (g_source_is_destroyed (g_main_current_source ())) {
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
);
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
;
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
))
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
);
1623 if (!nice_address_set_from_string (&externaddr
, external_ip
))
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 (
1640 local_candidate
->sockptr
);
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
);
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
;
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
);
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
);
1699 NICEAPI_EXPORT gboolean
1700 nice_agent_gather_candidates (
1707 GSList
*local_addresses
= NULL
;
1708 gboolean ret
= TRUE
;
1712 stream
= agent_find_stream (agent
, stream_id
);
1713 if (stream
== NULL
) {
1718 nice_debug ("Agent %p : In %s mode, starting candidate gathering.", agent
,
1719 agent
->full_mode
? "ICE-FULL" : "ICE-LITE");
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
);
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
);
1736 nice_debug ("Agent %p : Error creating UPnP Simple IGD agent", agent
);
1739 nice_debug ("Agent %p : UPnP property Disabled", agent
);
1742 nice_debug ("Agent %p : libnice compiled without UPnP support", agent
);
1745 /* if no local addresses added, generate them ourselves */
1746 if (agent
->local_addresses
== NULL
) {
1747 GList
*addresses
= nice_interfaces_get_local_ips (FALSE
);
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
);
1756 nice_address_free (addr
);
1760 g_list_foreach (addresses
, (GFunc
) g_free
, NULL
);
1761 g_list_free (addresses
);
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
;
1777 gchar local_ip
[NICE_ADDRESS_STRING_LEN
];
1778 nice_address_to_string (addr
, local_ip
);
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
);
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
,
1798 if (current_port
> 0)
1800 if (current_port
== 0 || current_port
> component
->max_port
)
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
);
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
),
1822 agent
->upnp_mapping
= g_slist_prepend (agent
->upnp_mapping
, addr
);
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
,
1840 if (agent
->full_mode
&& component
) {
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
,
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.",
1873 agent_gathering_done (agent
);
1875 g_assert (agent
->discovery_list
);
1876 discovery_schedule (agent
);
1880 for (i
= local_addresses
; i
; i
= i
->next
)
1881 nice_address_free (i
->data
);
1882 g_slist_free (local_addresses
);
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
);
1912 static void priv_free_upnp (NiceAgent
*agent
)
1918 g_object_unref (agent
->upnp
);
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
;
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
;
1947 nice_agent_remove_stream (
1951 /* note that streams/candidates can be in use by other threads */
1956 stream
= agent_find_stream (agent
, stream_id
);
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
);
1979 nice_agent_set_port_range (NiceAgent
*agent
, guint stream_id
, guint component_id
,
1980 guint min_port
, guint max_port
)
1982 Component
*component
;
1986 if (agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
)) {
1987 component
->min_port
= min_port
;
1988 component
->max_port
= max_port
;
1994 NICEAPI_EXPORT gboolean
1995 nice_agent_add_local_address (NiceAgent
*agent
, NiceAddress
*addr
)
2001 dup
= nice_address_dup (addr
);
2002 nice_address_set_port (dup
, 0);
2003 agent
->local_addresses
= g_slist_append (agent
->local_addresses
, dup
);
2009 static gboolean
priv_add_remote_candidate (
2013 NiceCandidateType type
,
2014 const NiceAddress
*addr
,
2015 const NiceAddress
*base_addr
,
2016 NiceCandidateTransport transport
,
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
))
2028 /* step: check whether the candidate already exists */
2029 candidate
= component_find_remote_candidate(component
, addr
, transport
);
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
;
2042 candidate
->base_addr
= *base_addr
;
2043 candidate
->priority
= priority
;
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 */
2058 g_free (candidate
->username
);
2059 candidate
->username
= g_strdup (username
);
2062 g_free (candidate
->password
);
2063 candidate
->password
= g_strdup (password
);
2065 if (conn_check_add_for_candidate (agent
, stream_id
, component
, candidate
) < 0)
2069 /* case 2: add a new candidate */
2071 candidate
= nice_candidate_new (type
);
2072 component
->remote_candidates
= g_slist_append (component
->remote_candidates
,
2075 candidate
->stream_id
= stream_id
;
2076 candidate
->component_id
= component_id
;
2078 candidate
->type
= type
;
2080 candidate
->addr
= *addr
;
2083 gchar tmpbuf
[INET6_ADDRSTRLEN
] = {0};
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
);
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
);
2101 g_strlcpy (candidate
->foundation
, foundation
,
2102 NICE_CANDIDATE_MAX_FOUNDATION
);
2104 if (conn_check_add_for_candidate (agent
, stream_id
, component
, candidate
) < 0)
2111 nice_candidate_free (candidate
);
2115 NICEAPI_EXPORT gboolean
2116 nice_agent_set_remote_credentials (
2119 const gchar
*ufrag
, const gchar
*pwd
)
2122 gboolean ret
= FALSE
;
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
);
2143 NICEAPI_EXPORT gboolean
2144 nice_agent_get_local_credentials (
2147 gchar
**ufrag
, gchar
**pwd
)
2150 gboolean ret
= TRUE
;
2154 stream
= agent_find_stream (agent
, stream_id
);
2155 if (stream
== NULL
) {
2159 if (!ufrag
|| !pwd
) {
2163 *ufrag
= g_strdup (stream
->local_ufrag
);
2164 *pwd
= g_strdup (stream
->local_password
);
2174 nice_agent_set_remote_candidates (NiceAgent
*agent
, guint stream_id
, guint component_id
, const GSList
*candidates
)
2179 Component
*component
;
2181 nice_debug ("Agent %p: set_remote_candidates %d %d", agent
, stream_id
, component_id
);
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
,
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
);
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
);
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
) {
2212 priv_add_remote_candidate (agent
,
2228 conn_check_remote_candidates_set(agent
);
2231 gboolean res
= conn_check_schedule_next (agent
);
2233 nice_debug ("Agent %p : Warning: unable to schedule any conn checks!", agent
);
2246 Component
*component
,
2255 len
= nice_socket_recv (socket
, &from
, buf_len
, buf
);
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
);
2270 if ((guint
)len
> buf_len
)
2272 /* buffer is not big enough to accept this packet */
2273 /* XXX: test this case */
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
)) {
2282 nice_debug ("Agent %p : Packet received from TURN server candidate.",
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
);
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 */
2307 if (conn_check_handle_inbound_stun (agent
, stream
, component
, socket
,
2309 /* handled STUN message*/
2312 /* unhandled STUN, pass to client */
2326 Component
*component
;
2331 if (!agent_find_component (agent
, stream_id
, component_id
,
2332 &stream
, &component
)) {
2336 if (component
->tcp
!= NULL
) {
2337 ret
= pseudo_tcp_socket_send (component
->tcp
, buf
, len
);
2338 adjust_tcp_clock (agent
, stream
, component
);
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");
2349 } else if (component
->selected_pair
.local
!= NULL
) {
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
,
2359 nice_address_get_port (&component
->selected_pair
.remote
->addr
));
2362 sock
= component
->selected_pair
.local
->sockptr
;
2363 addr
= &component
->selected_pair
.remote
->addr
;
2364 if (nice_socket_send (sock
, addr
, len
, buf
)) {
2376 NICEAPI_EXPORT GSList
*
2377 nice_agent_get_local_candidates (
2382 Component
*component
;
2383 GSList
* ret
= NULL
;
2384 GSList
* item
= NULL
;
2388 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
)) {
2392 for (item
= component
->local_candidates
; item
; item
= item
->next
)
2393 ret
= g_slist_append (ret
, nice_candidate_copy (item
->data
));
2401 NICEAPI_EXPORT GSList
*
2402 nice_agent_get_remote_candidates (
2407 Component
*component
;
2408 GSList
*ret
= NULL
, *item
= NULL
;
2411 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
2416 for (item
= component
->remote_candidates
; item
; item
= item
->next
)
2417 ret
= g_slist_append (ret
, nice_candidate_copy (item
->data
));
2426 nice_agent_restart (
2430 gboolean res
= TRUE
;
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
);
2454 nice_agent_dispose (GObject
*object
)
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
;
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
);
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
;
2522 GIOChannel
*channel
;
2526 Component
*component
;
2535 Component
*component
,
2537 GIOChannel
*channel
,
2542 ctx
= g_slice_new0 (IOCtx
);
2544 ctx
->stream
= stream
;
2545 ctx
->component
= component
;
2546 ctx
->socket
= socket
;
2547 ctx
->channel
= channel
;
2548 ctx
->source
= source
;
2555 io_ctx_free (IOCtx
*ctx
)
2557 g_io_channel_unref (ctx
->channel
);
2558 g_slice_free (IOCtx
, ctx
);
2562 nice_agent_g_source_cb (
2565 GIOCondition condition
,
2568 /* return value is whether to keep the source */
2571 NiceAgent
*agent
= ctx
->agent
;
2572 Stream
*stream
= ctx
->stream
;
2573 Component
*component
= ctx
->component
;
2574 gchar buf
[MAX_BUFFER_SIZE
];
2579 if (g_source_is_destroyed (g_main_current_source ())) {
2584 /* note: dear compiler, these are for you: */
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
);
2594 adjust_tcp_clock (agent
, stream
, component
);
2595 g_object_remove_weak_pointer (G_OBJECT (agent
), (gpointer
*)&agent
);
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 */
2608 callback (agent
, sid
, cid
, len
, buf
, data
);
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
,
2633 * Attaches one socket handle to the main loop event context
2637 agent_attach_stream_component_socket (NiceAgent
*agent
,
2639 Component
*component
,
2646 if (!component
->ctx
)
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
2668 priv_attach_stream_component (NiceAgent
*agent
,
2670 Component
*component
)
2674 for (i
= component
->sockets
; i
; i
= i
->next
)
2675 agent_attach_stream_component_socket (agent
, stream
, component
, i
->data
);
2681 * Detaches socket handles of 'stream' from the main eventloop
2685 static void priv_detach_stream_component (Stream
*stream
, Component
*component
)
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 (
2706 NiceAgentRecvFunc func
,
2709 Component
*component
= NULL
;
2710 Stream
*stream
= NULL
;
2711 gboolean ret
= FALSE
;
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
,
2724 if (component
->g_source_io_cb
)
2725 priv_detach_stream_component (stream
, component
);
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
);
2746 component
->g_source_io_cb
= NULL
;
2747 component
->data
= NULL
;
2748 component
->ctx
= NULL
;
2757 NICEAPI_EXPORT gboolean
2758 nice_agent_set_selected_pair (
2762 const gchar
*lfoundation
,
2763 const gchar
*rfoundation
)
2765 Component
*component
;
2768 gboolean ret
= FALSE
;
2772 /* step: check that params specify an existing pair */
2773 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
2777 if (!component_find_pair (component
, agent
, lfoundation
, rfoundation
, &pair
)){
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
);
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
);
2806 GSource
* agent_timeout_add_with_context (NiceAgent
*agent
, guint interval
,
2807 GSourceFunc function
, gpointer data
)
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
);
2823 NICEAPI_EXPORT gboolean
2824 nice_agent_set_selected_remote_candidate (
2828 NiceCandidate
*candidate
)
2830 Component
*component
;
2832 NiceCandidate
*lcandidate
= NULL
;
2833 gboolean ret
= FALSE
;
2837 /* step: check if the component exists*/
2838 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
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
);
2853 /* step: set the selected pair */
2854 lcandidate
= component_set_selected_remote_candidate (agent
, component
,
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
);
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
));
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
));
2891 void nice_agent_set_stream_tos (NiceAgent
*agent
,
2892 guint stream_id
, gint tos
)
2899 for (i
= agent
->streams
; i
; i
= i
->next
) {
2900 Stream
*stream
= i
->data
;
2901 if (stream
->id
== stream_id
) {
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
);
2917 void nice_agent_set_software (NiceAgent
*agent
, const gchar
*software
)
2921 g_free (agent
->software_attribute
);
2923 agent
->software_attribute
= g_strdup_printf ("%s/%s",
2924 software
, PACKAGE_STRING
);
2926 stun_agent_set_software (&agent
->stun_agent
, agent
->software_attribute
);