2 * This file is part of the Nice GLib ICE library.
4 * (C) 2006, 2007 Collabora Ltd.
5 * Contact: Dafydd Harries
6 * (C) 2006, 2007 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.
28 * Alternatively, the contents of this file may be used under the terms of the
29 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
30 * case the provisions of LGPL are applicable instead of those above. If you
31 * wish to allow use of your version of this file only under the terms of the
32 * LGPL and not to allow others to use your version of this file under the
33 * MPL, indicate your decision by deleting the provisions above and replace
34 * them with the notice and other provisions required by the LGPL. If you do
35 * not delete the provisions above, a recipient may use your version of this
36 * file under either the MPL or the LGPL.
41 * @brief ICE agent API implementation
51 #include <sys/select.h>
52 #include <sys/socket.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
61 #include "candidate.h"
62 #include "component.h"
63 #include "conncheck.h"
64 #include "discovery.h"
66 #include "agent-priv.h"
67 #include "agent-signals-marshal.h"
71 /* This is the max size of a UDP packet
72 * will it work tcp relaying??
74 #define MAX_BUFFER_SIZE 65536
75 #define DEFAULT_STUN_PORT 3478
78 G_DEFINE_TYPE (NiceAgent
, nice_agent
, G_TYPE_OBJECT
);
82 PROP_COMPATIBILITY
= 1,
85 PROP_STUN_SERVER_PORT
,
86 PROP_CONTROLLING_MODE
,
88 PROP_STUN_PACING_TIMER
,
89 PROP_MAX_CONNECTIVITY_CHECKS
95 SIGNAL_COMPONENT_STATE_CHANGED
,
96 SIGNAL_CANDIDATE_GATHERING_DONE
,
97 SIGNAL_NEW_SELECTED_PAIR
,
99 SIGNAL_NEW_REMOTE_CANDIDATE
,
100 SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED
,
105 static guint signals
[N_SIGNALS
];
107 static gboolean
priv_attach_stream_component (NiceAgent
*agent
,
109 Component
*component
);
110 static void priv_detach_stream_component (Stream
*stream
, Component
*component
);
112 Stream
*agent_find_stream (NiceAgent
*agent
, guint stream_id
)
116 for (i
= agent
->streams
; i
; i
= i
->next
)
120 if (s
->id
== stream_id
)
129 agent_find_component (
134 Component
**component
)
139 s
= agent_find_stream (agent
, stream_id
);
144 c
= stream_find_component_by_id (s
, component_id
);
160 nice_agent_dispose (GObject
*object
);
163 nice_agent_get_property (
170 nice_agent_set_property (
178 nice_agent_class_init (NiceAgentClass
*klass
)
180 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
182 gobject_class
->get_property
= nice_agent_get_property
;
183 gobject_class
->set_property
= nice_agent_set_property
;
184 gobject_class
->dispose
= nice_agent_dispose
;
186 /* install properties */
188 g_object_class_install_property (gobject_class
, PROP_MAIN_CONTEXT
,
189 g_param_spec_pointer (
191 "The GMainContext to use for timeouts",
192 "The GMainContext to use for timeouts",
193 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
195 g_object_class_install_property (gobject_class
, PROP_COMPATIBILITY
,
198 "ICE specification compatibility",
199 "The compatibility mode for the agent",
200 NICE_COMPATIBILITY_ID19
, NICE_COMPATIBILITY_LAST
,
201 NICE_COMPATIBILITY_ID19
,
202 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
204 g_object_class_install_property (gobject_class
, PROP_STUN_SERVER
,
205 g_param_spec_string (
208 "The STUN server used to obtain server-reflexive candidates",
212 g_object_class_install_property (gobject_class
, PROP_STUN_SERVER_PORT
,
216 "The STUN server used to obtain server-reflexive candidates",
218 1, /* not a construct property, ignored */
221 g_object_class_install_property (gobject_class
, PROP_CONTROLLING_MODE
,
222 g_param_spec_boolean (
224 "ICE controlling mode",
225 "Whether the agent is in controlling mode",
226 FALSE
, /* not a construct property, ignored */
229 g_object_class_install_property (gobject_class
, PROP_FULL_MODE
,
230 g_param_spec_boolean (
233 "Whether agent runs in ICE full mode",
234 TRUE
, /* use full mode by default */
235 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
237 g_object_class_install_property (gobject_class
, PROP_STUN_PACING_TIMER
,
241 "Timer 'Ta' (msecs) used in the IETF ICE specification for pacing candidate gathering and sending of connectivity checks",
243 NICE_AGENT_TIMER_TA_DEFAULT
,
244 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
246 /* note: according to spec recommendation in sect 5.7.3 (ID-19) */
247 g_object_class_install_property (gobject_class
, PROP_MAX_CONNECTIVITY_CHECKS
,
249 "max-connectivity-checks",
250 "Maximum number of connectivity checks",
251 "Upper limit for the total number of connectivity checks performed",
253 0, /* default set in init */
256 /* install signals */
258 /* signature: void cb(NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer self) */
259 signals
[SIGNAL_COMPONENT_STATE_CHANGED
] =
261 "component-state-changed",
262 G_OBJECT_CLASS_TYPE (klass
),
263 G_SIGNAL_RUN_LAST
| G_SIGNAL_DETAILED
,
267 agent_marshal_VOID__UINT_UINT_UINT
,
270 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_UINT
,
273 /* signature: void cb(NiceAgent *agent, gpointer self) */
274 signals
[SIGNAL_CANDIDATE_GATHERING_DONE
] =
276 "candidate-gathering-done",
277 G_OBJECT_CLASS_TYPE (klass
),
278 G_SIGNAL_RUN_LAST
| G_SIGNAL_DETAILED
,
282 agent_marshal_VOID__VOID
,
287 /* signature: void cb(NiceAgent *agent, guint stream_id, guint component_id,
288 gchar *lfoundation, gchar* rfoundation, gpointer self) */
289 signals
[SIGNAL_NEW_SELECTED_PAIR
] =
292 G_OBJECT_CLASS_TYPE (klass
),
293 G_SIGNAL_RUN_LAST
| G_SIGNAL_DETAILED
,
297 agent_marshal_VOID__UINT_UINT_STRING_STRING
,
300 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_STRING
, G_TYPE_STRING
,
303 /* signature: void cb(NiceAgent *agent, guint stream_id, guint component_id, gchar *foundation) */
304 signals
[SIGNAL_NEW_CANDIDATE
] =
307 G_OBJECT_CLASS_TYPE (klass
),
308 G_SIGNAL_RUN_LAST
| G_SIGNAL_DETAILED
,
312 agent_marshal_VOID__UINT_UINT_STRING
,
315 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_STRING
,
318 /* signature: void cb(NiceAgent *agent, guint stream_id, guint component_id, gchar *foundation) */
319 signals
[SIGNAL_NEW_REMOTE_CANDIDATE
] =
321 "new-remote-candidate",
322 G_OBJECT_CLASS_TYPE (klass
),
323 G_SIGNAL_RUN_LAST
| G_SIGNAL_DETAILED
,
327 agent_marshal_VOID__UINT_UINT_STRING
,
330 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_STRING
,
333 /* signature: void cb(NiceAgent *agent, guint stream_id, gpointer self) */
334 signals
[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED
] =
336 "initial-binding-request-received",
337 G_OBJECT_CLASS_TYPE (klass
),
338 G_SIGNAL_RUN_LAST
| G_SIGNAL_DETAILED
,
342 agent_marshal_VOID__UINT
,
350 static void priv_generate_tie_breaker (NiceAgent
*agent
)
352 nice_rng_generate_bytes (agent
->rng
, 8, (gchar
*)&agent
->tie_breaker
);
356 nice_agent_init (NiceAgent
*agent
)
358 agent
->next_candidate_id
= 1;
359 agent
->next_stream_id
= 1;
361 /* set defaults; not construct params, so set here */
362 agent
->stun_server_port
= DEFAULT_STUN_PORT
;
363 agent
->controlling_mode
= TRUE
;
364 agent
->max_conn_checks
= NICE_AGENT_MAX_CONNECTIVITY_CHECKS_DEFAULT
;
366 agent
->discovery_list
= NULL
;
367 agent
->discovery_unsched_items
= 0;
368 agent
->discovery_timer_id
= 0;
369 agent
->conncheck_timer_id
= 0;
370 agent
->keepalive_timer_id
= 0;
371 agent
->compatibility
= NICE_COMPATIBILITY_ID19
;
373 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
374 STUN_COMPATIBILITY_3489BIS
,
375 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
376 STUN_AGENT_USAGE_USE_FINGERPRINT
);
378 nice_udp_bsd_socket_factory_init (&agent
->udp_socket_factory
);
379 nice_udp_turn_socket_factory_init (&agent
->relay_socket_factory
);
381 agent
->rng
= nice_rng_new ();
382 priv_generate_tie_breaker (agent
);
384 g_static_rec_mutex_init (&agent
->mutex
);
391 * Create a new NiceAgent.
393 * Returns: the new agent
395 NICEAPI_EXPORT NiceAgent
*
396 nice_agent_new (GMainContext
*ctx
, NiceCompatibility compat
)
398 NiceAgent
*agent
= g_object_new (NICE_TYPE_AGENT
,
399 "compatibility", compat
,
408 nice_agent_get_property (
414 NiceAgent
*agent
= NICE_AGENT (object
);
416 g_static_rec_mutex_lock (&agent
->mutex
);
420 case PROP_MAIN_CONTEXT
:
421 g_value_set_pointer (value
, agent
->main_context
);
424 case PROP_COMPATIBILITY
:
425 g_value_set_uint (value
, agent
->compatibility
);
428 case PROP_STUN_SERVER
:
429 g_value_set_string (value
, agent
->stun_server_ip
);
432 case PROP_STUN_SERVER_PORT
:
433 g_value_set_uint (value
, agent
->stun_server_port
);
436 case PROP_CONTROLLING_MODE
:
437 g_value_set_boolean (value
, agent
->controlling_mode
);
441 g_value_set_boolean (value
, agent
->full_mode
);
444 case PROP_STUN_PACING_TIMER
:
445 g_value_set_uint (value
, agent
->timer_ta
);
448 case PROP_MAX_CONNECTIVITY_CHECKS
:
449 g_value_set_uint (value
, agent
->max_conn_checks
);
450 /* XXX: should we prune the list of already existing checks? */
454 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
457 g_static_rec_mutex_unlock (&agent
->mutex
);
462 nice_agent_set_property (
468 NiceAgent
*agent
= NICE_AGENT (object
);
470 g_static_rec_mutex_lock (&agent
->mutex
);
474 case PROP_MAIN_CONTEXT
:
475 agent
->main_context
= g_value_get_pointer (value
);
478 case PROP_COMPATIBILITY
:
479 agent
->compatibility
= g_value_get_uint (value
);
480 if (agent
->compatibility
== NICE_COMPATIBILITY_ID19
) {
481 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
482 STUN_COMPATIBILITY_3489BIS
,
483 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
484 STUN_AGENT_USAGE_USE_FINGERPRINT
);
485 } else if (agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
) {
486 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
487 STUN_COMPATIBILITY_RFC3489
,
488 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
489 STUN_AGENT_USAGE_IGNORE_CREDENTIALS
);
490 } else if (agent
->compatibility
== NICE_COMPATIBILITY_MSN
) {
491 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
492 STUN_COMPATIBILITY_RFC3489
,
493 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
494 STUN_AGENT_USAGE_FORCE_VALIDATER
);
499 case PROP_STUN_SERVER
:
500 agent
->stun_server_ip
= g_value_dup_string (value
);
503 case PROP_STUN_SERVER_PORT
:
504 agent
->stun_server_port
= g_value_get_uint (value
);
507 case PROP_CONTROLLING_MODE
:
508 agent
->controlling_mode
= g_value_get_boolean (value
);
512 agent
->full_mode
= g_value_get_boolean (value
);
515 case PROP_STUN_PACING_TIMER
:
516 agent
->timer_ta
= g_value_get_uint (value
);
519 case PROP_MAX_CONNECTIVITY_CHECKS
:
520 agent
->max_conn_checks
= g_value_get_uint (value
);
524 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
527 g_static_rec_mutex_unlock (&agent
->mutex
);
531 void agent_gathering_done (NiceAgent
*agent
)
534 GSList
*i
, *j
, *k
, *l
, *m
;
536 for (i
= agent
->streams
; i
; i
= i
->next
) {
537 Stream
*stream
= i
->data
;
538 for (j
= stream
->components
; j
; j
= j
->next
) {
539 Component
*component
= j
->data
;
541 for (k
= component
->local_candidates
; k
; k
= k
->next
) {
542 NiceCandidate
*local_candidate
= k
->data
;
544 for (l
= component
->remote_candidates
; l
; l
= l
->next
) {
545 NiceCandidate
*remote_candidate
= l
->data
;
547 for (m
= stream
->conncheck_list
; m
; m
= m
->next
) {
548 CandidateCheckPair
*p
= m
->data
;
550 if (p
->local
== local_candidate
&& p
->remote
== remote_candidate
)
554 conn_check_add_for_candidate (agent
, stream
->id
, component
, remote_candidate
);
561 agent_signal_gathering_done (agent
);
564 void agent_signal_gathering_done (NiceAgent
*agent
)
566 g_signal_emit (agent
, signals
[SIGNAL_CANDIDATE_GATHERING_DONE
], 0);
569 void agent_signal_initial_binding_request_received (NiceAgent
*agent
, Stream
*stream
)
571 if (stream
->initial_binding_request_received
!= TRUE
) {
572 stream
->initial_binding_request_received
= TRUE
;
573 g_signal_emit (agent
, signals
[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED
], 0, stream
->id
);
577 void agent_signal_new_selected_pair (NiceAgent
*agent
, guint stream_id
, guint component_id
, const gchar
*local_foundation
, const gchar
*remote_foundation
)
579 Component
*component
;
583 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
586 lf_copy
= g_strdup (local_foundation
);
587 rf_copy
= g_strdup (remote_foundation
);
590 g_signal_emit (agent
, signals
[SIGNAL_NEW_SELECTED_PAIR
], 0,
591 stream_id
, component_id
, lf_copy
, rf_copy
);
597 void agent_signal_new_candidate (NiceAgent
*agent
, NiceCandidate
*candidate
)
599 g_signal_emit (agent
, signals
[SIGNAL_NEW_CANDIDATE
], 0,
600 candidate
->stream_id
,
601 candidate
->component_id
,
602 candidate
->foundation
);
605 void agent_signal_new_remote_candidate (NiceAgent
*agent
, NiceCandidate
*candidate
)
607 g_signal_emit (agent
, signals
[SIGNAL_NEW_REMOTE_CANDIDATE
], 0,
608 candidate
->stream_id
,
609 candidate
->component_id
,
610 candidate
->foundation
);
613 void agent_signal_component_state_change (NiceAgent
*agent
, guint stream_id
, guint component_id
, NiceComponentState state
)
615 Component
*component
;
617 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
620 if (component
->state
!= state
&& state
< NICE_COMPONENT_STATE_LAST
) {
621 g_debug ("Agent %p : stream %u component %u STATE-CHANGE %u -> %u.", agent
,
622 stream_id
, component_id
, component
->state
, state
);
624 component
->state
= state
;
626 g_signal_emit (agent
, signals
[SIGNAL_COMPONENT_STATE_CHANGED
], 0,
627 stream_id
, component_id
, state
);
632 agent_candidate_pair_priority (NiceAgent
*agent
, NiceCandidate
*local
, NiceCandidate
*remote
)
634 if (agent
->controlling_mode
)
635 return nice_candidate_pair_priority (local
->priority
, remote
->priority
);
637 return nice_candidate_pair_priority (remote
->priority
, local
->priority
);
641 priv_add_new_candidate_discovery (NiceAgent
*agent
,
642 NiceCandidate
*host_candidate
, NiceAddress server
,
643 Stream
*stream
, guint component_id
,
644 NiceAddress
*addr
, NiceCandidateType type
)
646 CandidateDiscovery
*cdisco
;
647 GSList
*modified_list
;
649 /* note: no need to check for redundant candidates, as this is
650 * done later on in the process */
652 cdisco
= g_slice_new0 (CandidateDiscovery
);
654 modified_list
= g_slist_append (agent
->discovery_list
, cdisco
);
658 cdisco
->socket
= host_candidate
->sockptr
->fileno
;
659 cdisco
->nicesock
= host_candidate
->sockptr
;
660 cdisco
->server
= server
;
661 cdisco
->interface
= addr
;
662 cdisco
->stream
= stream
;
663 cdisco
->component
= stream_find_component_by_id (stream
, component_id
);
664 cdisco
->agent
= agent
;
665 g_debug ("Agent %p : Adding new srv-rflx candidate discovery %p\n", agent
, cdisco
);
666 agent
->discovery_list
= modified_list
;
667 ++agent
->discovery_unsched_items
;
678 * nice_agent_add_stream:
679 * @agent: a NiceAgent
680 * @n_components: number of components
682 * Add a data stream to @agent.
684 * @pre local addresses must be set with nice_agent_add_local_address()
686 * Returns: the ID of the new stream, 0 on failure
689 nice_agent_add_stream (
694 GSList
*modified_list
= NULL
;
697 g_static_rec_mutex_lock (&agent
->mutex
);
699 if (!agent
->local_addresses
) {
700 g_warn_if_fail(agent
->local_addresses
);
704 stream
= stream_new (n_components
);
706 modified_list
= g_slist_append (agent
->streams
, stream
);
708 stream
->id
= agent
->next_stream_id
++;
709 g_debug ("Agent %p : allocating stream id %u (%p)", agent
, stream
->id
, stream
);
711 stream_initialize_credentials (stream
, agent
->rng
);
713 agent
->streams
= modified_list
;
716 stream_free (stream
);
722 g_static_rec_mutex_unlock (&agent
->mutex
);
727 NICEAPI_EXPORT
void nice_agent_set_relay_info(NiceAgent
*agent
,
728 guint stream_id
, guint component_id
,
729 const gchar
*server_ip
, guint server_port
,
730 const gchar
*username
, const gchar
*password
)
733 Component
*component
= NULL
;
735 g_static_rec_mutex_lock (&agent
->mutex
);
737 if (agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
)) {
738 nice_address_init (&component
->turn_server
);
740 if (nice_address_set_from_string (&component
->turn_server
, server_ip
)) {
741 nice_address_set_port (&component
->turn_server
, server_port
);
744 g_free (component
->turn_username
);
745 component
->turn_username
= g_strdup (username
);
747 g_free (component
->turn_password
);
748 component
->turn_password
= g_strdup (password
);
750 g_static_rec_mutex_unlock (&agent
->mutex
);
755 * nice_agent_gather_candidates:
757 * start the candidate gathering process
761 nice_agent_gather_candidates (
769 g_static_rec_mutex_lock (&agent
->mutex
);
771 stream
= agent_find_stream (agent
, stream_id
);
772 if (stream
== NULL
) {
776 g_debug ("Agent %p : In %s mode, starting candidate gathering.", agent
, agent
->full_mode
? "ICE-FULL" : "ICE-LITE");
778 /* generate a local host candidate for each local address */
780 for (i
= agent
->local_addresses
; i
; i
= i
->next
)
782 NiceAddress
*addr
= i
->data
;
783 NiceCandidate
*host_candidate
;
785 for (n
= 0; n
< stream
->n_components
; n
++) {
786 Component
*component
= stream_find_component_by_id (stream
, n
+ 1);
787 host_candidate
= discovery_add_local_host_candidate (agent
, stream
->id
,
790 if (!host_candidate
) {
791 g_error ("No host candidate??");
795 if (agent
->full_mode
&&
796 agent
->stun_server_ip
) {
797 NiceAddress stun_server
;
798 if (nice_address_set_from_string (&stun_server
, agent
->stun_server_ip
)) {
799 nice_address_set_port (&stun_server
, agent
->stun_server_port
);
802 priv_add_new_candidate_discovery (agent
,
806 n
+ 1 /* component-id */,
808 NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE
);
811 /* note: memory allocation failure, return error */
812 g_error ("Memory allocation failure?");
816 if (agent
->full_mode
&&
817 component
&& nice_address_is_valid (&component
->turn_server
)) {
820 priv_add_new_candidate_discovery (agent
,
822 component
->turn_server
,
824 n
+ 1 /* component-id */,
826 NICE_CANDIDATE_TYPE_RELAYED
);
829 /* note: memory allocation failure, return error */
830 g_error ("Memory allocation failure?");
837 /* note: no async discoveries pending, signal that we are ready */
838 if (agent
->discovery_unsched_items
== 0) {
839 agent_gathering_done (agent
);
841 g_assert (agent
->discovery_list
);
842 discovery_schedule (agent
);
847 g_static_rec_mutex_unlock (&agent
->mutex
);
850 static void priv_remove_keepalive_timer (NiceAgent
*agent
)
852 if (agent
->keepalive_timer_id
) {
853 g_source_remove (agent
->keepalive_timer_id
),
854 agent
->keepalive_timer_id
= 0;
859 * nice_agent_remove_stream:
860 * @agent: a NiceAgent
861 * @stream_id: the ID of the stream to remove
864 nice_agent_remove_stream (
868 /* note that streams/candidates can be in use by other threads */
873 g_static_rec_mutex_lock (&agent
->mutex
);
874 stream
= agent_find_stream (agent
, stream_id
);
880 /* note: remove items with matching stream_ids from both lists */
881 conn_check_prune_stream (agent
, stream
);
882 discovery_prune_stream (agent
, stream_id
);
884 /* remove the stream itself */
885 for (i
= stream
->components
; i
; i
= i
->next
) {
886 priv_detach_stream_component (stream
, (Component
*) i
->data
);
889 agent
->streams
= g_slist_remove (agent
->streams
, stream
);
890 stream_free (stream
);
893 priv_remove_keepalive_timer (agent
);
896 g_static_rec_mutex_unlock (&agent
->mutex
);
900 * nice_agent_add_local_address:
901 * @agent: A NiceAgent
902 * @addr: the address of a local IP interface
904 * Inform the agent of the presence of an address that a local
905 * network interface is bound to.
907 * @return FALSE on fatal (memory allocation) errors
909 NICEAPI_EXPORT gboolean
910 nice_agent_add_local_address (NiceAgent
*agent
, NiceAddress
*addr
)
913 GSList
*modified_list
;
914 gboolean ret
= FALSE
;
916 g_static_rec_mutex_lock (&agent
->mutex
);
918 dup
= nice_address_dup (addr
);
919 nice_address_set_port (dup
, 0);
920 modified_list
= g_slist_append (agent
->local_addresses
, dup
);
922 agent
->local_addresses
= modified_list
;
929 g_static_rec_mutex_unlock (&agent
->mutex
);
934 * Adds a new, or updates an existing, remote candidate.
936 * @return TRUE if candidate was succesfully added or
937 * update, otherwise FALSE
939 static gboolean
priv_add_remote_candidate (
943 NiceCandidateType type
,
944 const NiceAddress
*addr
,
945 const NiceAddress
*base_addr
,
946 NiceCandidateTransport transport
,
948 const gchar
*username
,
949 const gchar
*password
,
950 const gchar
*foundation
)
952 Component
*component
;
953 NiceCandidate
*candidate
;
954 gchar
*username_dup
= NULL
, *password_dup
= NULL
;
955 gboolean error_flag
= FALSE
;
957 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
960 /* step: check whether the candidate already exists */
961 candidate
= component_find_remote_candidate(component
, addr
, transport
);
963 g_debug ("Agent %p : Update existing remote candidate %p.", agent
, candidate
);
964 /* case 1: an existing candidate, update the attributes */
965 candidate
->type
= type
;
967 candidate
->base_addr
= *base_addr
;
968 candidate
->priority
= priority
;
970 strncpy(candidate
->foundation
, foundation
, NICE_CANDIDATE_MAX_FOUNDATION
);
971 /* note: username and password must remain the same during
972 * a session; see sect 9.1.2 in ICE ID-19 */
973 if (conn_check_add_for_candidate (agent
, stream_id
, component
, candidate
) < 0)
977 /* case 2: add a new candidate */
979 username_dup
= g_strdup (username
);
981 password_dup
= g_strdup (password
);
983 candidate
= nice_candidate_new (type
);
985 GSList
*modified_list
= g_slist_append (component
->remote_candidates
, candidate
);
987 component
->remote_candidates
= modified_list
;
989 candidate
->stream_id
= stream_id
;
990 candidate
->component_id
= component_id
;
992 candidate
->type
= type
;
994 candidate
->addr
= *addr
;
997 gchar tmpbuf
[INET6_ADDRSTRLEN
];
998 nice_address_to_string (addr
, tmpbuf
);
999 g_debug ("Agent %p : Adding remote candidate with addr [%s]:%u.", agent
, tmpbuf
,
1000 nice_address_get_port (addr
));
1005 candidate
->base_addr
= *base_addr
;
1007 candidate
->transport
= transport
;
1008 candidate
->priority
= priority
;
1009 candidate
->username
= username_dup
;
1010 candidate
->password
= password_dup
;
1013 g_strlcpy (candidate
->foundation
, foundation
, NICE_CANDIDATE_MAX_FOUNDATION
);
1015 if (conn_check_add_for_candidate (agent
, stream_id
, component
, candidate
) < 0)
1018 else /* memory alloc error: list insert */
1021 else /* memory alloc error: candidate creation */
1027 nice_candidate_free (candidate
);
1028 g_free (username_dup
);
1029 g_free (password_dup
);
1037 * Sets the remote credentials for stream 'stream_id'.
1039 * Note: stream credentials do not override per-candidate
1040 * credentials if set
1042 * @agent: a NiceAgent
1043 * @stream_id: identifier returnedby nice_agent_add_stream()
1044 * @ufrag: NULL-terminated string containing an ICE username fragment
1045 * (length must be between 22 and 256 chars)
1046 * @pwd: NULL-terminated string containing an ICE password
1047 * (length must be between 4 and 256 chars)
1049 * @return TRUE on success
1051 NICEAPI_EXPORT gboolean
1052 nice_agent_set_remote_credentials (
1055 const gchar
*ufrag
, const gchar
*pwd
)
1058 gboolean ret
= FALSE
;
1060 g_static_rec_mutex_lock (&agent
->mutex
);
1062 stream
= agent_find_stream (agent
, stream_id
);
1063 /* note: oddly enough, ufrag and pwd can be empty strings */
1064 if (stream
&& ufrag
&& pwd
) {
1066 g_strlcpy (stream
->remote_ufrag
, ufrag
, NICE_STREAM_MAX_UFRAG
);
1067 g_strlcpy (stream
->remote_password
, pwd
, NICE_STREAM_MAX_PWD
);
1074 g_static_rec_mutex_unlock (&agent
->mutex
);
1079 * Gets the local credentials for stream 'stream_id'.
1081 * @agent: a NiceAgent
1082 * @stream_id: identifier returnedby nice_agent_add_stream()
1083 * @ufrag: a pointer to a NULL-terminated string containing
1084 * an ICE username fragment [OUT]
1085 * @pwd: a pointer to a NULL-terminated string containing an ICE
1088 * @return TRUE on success
1090 NICEAPI_EXPORT gboolean
1091 nice_agent_get_local_credentials (
1094 const gchar
**ufrag
, const gchar
**pwd
)
1097 gboolean ret
= TRUE
;
1099 g_static_rec_mutex_lock (&agent
->mutex
);
1101 stream
= agent_find_stream (agent
, stream_id
);
1102 if (stream
== NULL
) {
1106 if (!ufrag
|| !pwd
) {
1110 *ufrag
= stream
->local_ufrag
;
1111 *pwd
= stream
->local_password
;
1116 g_static_rec_mutex_unlock (&agent
->mutex
);
1121 * nice_agent_add_remote_candidate
1122 * @agent: a NiceAgent
1123 * @stream_id: the ID of the stream the candidate is for
1124 * @component_id: the ID of the component the candidate is for
1125 * @type: the type of the new candidate
1126 * @addr: the new candidate's IP address
1127 * @username: the new candidate's username (XXX: candidates don't have usernames)
1128 * @password: the new candidate's password (XXX: candidates don't have usernames)
1130 * Add a candidate our peer has informed us about to the agent's list.
1132 * Note: NICE_AGENT_MAX_REMOTE_CANDIDATES is the absolute
1133 * maximum limit for remote candidates
1134 * @return FALSE on fatal (memory alloc) errors
1136 NICEAPI_EXPORT gboolean
1137 nice_agent_add_remote_candidate (
1141 NiceCandidateType type
,
1143 const gchar
*username
,
1144 const gchar
*password
)
1147 /* XXX: to be deprecated */
1149 g_static_rec_mutex_lock (&agent
->mutex
);
1151 /* XXX: should we allow use of this method without an
1152 * initial call to nice_agent_set_remote_candidates()
1153 * with an empty set? */
1156 priv_add_remote_candidate (agent
,
1162 NICE_CANDIDATE_TRANSPORT_UDP
,
1168 /* XXX/later: for each component, generate a new check with the new
1169 candidate, see below set_remote_candidates() */
1172 g_static_rec_mutex_unlock (&agent
->mutex
);
1177 * nice_agent_set_remote_candidates
1178 * @agent: a NiceAgent
1179 * @stream_id: the ID of the stream the candidate is for
1180 * @component_id: the ID of the component the candidate is for
1181 * @candidates: a list of NiceCandidate items describing the candidates
1183 * Sets the remote candidates for a component of a stream. Replaces
1184 * any existing remote candidates.
1186 * Note: NICE_AGENT_MAX_REMOTE_CANDIDATES is the absolute
1187 * maximum limit for remote candidates
1189 * @return number of candidates added, negative on fatal (memory
1193 nice_agent_set_remote_candidates (NiceAgent
*agent
, guint stream_id
, guint component_id
, const GSList
*candidates
)
1199 if (agent
->discovery_unsched_items
> 0)
1202 g_static_rec_mutex_lock (&agent
->mutex
);
1204 for (i
= candidates
; i
&& added
>= 0; i
= i
->next
) {
1205 NiceCandidate
*d
= (NiceCandidate
*) i
->data
;
1207 priv_add_remote_candidate (agent
,
1224 conn_check_remote_candidates_set(agent
);
1227 gboolean res
= conn_check_schedule_next (agent
);
1229 g_debug ("Agent %p : Warning: unable to schedule any conn checks!", agent
);
1232 g_static_rec_mutex_unlock (&agent
->mutex
);
1238 * Reads data from a ready, nonblocking socket attached to an ICE
1241 * @return number of octets received, or negative on error
1247 Component
*component
,
1248 NiceUDPSocket
*udp_socket
,
1255 len
= nice_udp_socket_recv (udp_socket
, &from
,
1260 gchar tmpbuf
[INET6_ADDRSTRLEN
];
1261 nice_address_to_string (&from
, tmpbuf
);
1262 g_debug ("Agent %p : Packet received on local socket %u from [%s]:%u (%u octets).", agent
,
1263 udp_socket
->fileno
, tmpbuf
, nice_address_get_port (&from
), len
);
1270 if ((guint
)len
> buf_len
)
1272 /* buffer is not big enough to accept this packet */
1273 /* XXX: test this case */
1277 if (nice_address_equal (&from
, &component
->turn_server
)) {
1279 g_debug ("Agent %p : Packet received from TURN server candidate.", agent
);
1280 for (i
= component
->local_candidates
; i
; i
= i
->next
) {
1281 NiceCandidate
*cand
= i
->data
;
1282 if (cand
->type
== NICE_CANDIDATE_TYPE_RELAYED
) {
1283 len
= nice_udp_turn_socket_parse_recv (cand
->sockptr
, &from
, len
, buf
, &from
, buf
, len
);
1288 if (!stun_message_validate_buffer_length ((uint8_t *) buf
, (size_t) len
) ==
1290 /* If the retval is no 0, its not a valid stun packet, probably data */
1294 if (conn_check_handle_inbound_stun (agent
, stream
, component
, udp_socket
,
1296 /* handled STUN message*/
1299 /* unhandled STUN, pass to client */
1305 * @agent: a NiceAgent
1306 * @stream_id: the ID of the stream to recieve data from
1307 * @component_id: the ID of the component to receive data from
1308 * @buf_len: the size of @buf
1309 * @buf: the buffer to read data into
1311 * Receive data on a particular component.
1313 * Returns: the amount of data read into @buf
1315 NICEAPI_EXPORT guint
1329 Component
*component
;
1332 g_static_rec_mutex_lock (&agent
->mutex
);
1333 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1339 for (i
= component
->sockets
; i
; i
= i
->next
)
1341 NiceUDPSocket
*sockptr
= i
->data
;
1343 FD_SET (sockptr
->fileno
, &fds
);
1344 max_fd
= MAX (sockptr
->fileno
, max_fd
);
1347 /* Loop on candidate sockets until we find one that has non-STUN data
1353 num_readable
= select (max_fd
+ 1, &fds
, NULL
, NULL
, NULL
);
1354 g_assert (num_readable
>= 0);
1356 if (num_readable
> 0)
1360 for (j
= 0; j
<= max_fd
; j
++)
1361 if (FD_ISSET (j
, &fds
))
1363 NiceUDPSocket
*socket
;
1365 socket
= component_find_udp_socket_by_fd (component
, j
);
1368 len
= _nice_agent_recv (agent
, stream
, component
, socket
,
1379 /* note: commented out to avoid compiler warnings
1381 * g_assert_not_reached (); */
1383 g_static_rec_mutex_unlock (&agent
->mutex
);
1387 NICEAPI_EXPORT guint
1388 nice_agent_recv_sock (
1396 NiceUDPSocket
*socket
;
1398 Component
*component
;
1401 g_static_rec_mutex_lock (&agent
->mutex
);
1402 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1406 socket
= component_find_udp_socket_by_fd (component
, sock
);
1409 ret
= _nice_agent_recv (agent
, stream
, component
,
1410 socket
, buf_len
, buf
);
1413 g_static_rec_mutex_unlock (&agent
->mutex
);
1419 * nice_agent_poll_read:
1420 * @agent: A NiceAgent
1421 * @other_fds: A GSList of other file descriptors to poll
1423 * Polls the agent's sockets until at least one of them is readable, and
1424 * additionally if @other_fds is not NULL, polls those for readability too.
1425 * @other_fds should contain the file descriptors directly, i.e. using
1428 * Returns: A list of file descriptors from @other_fds that are readable
1430 NICEAPI_EXPORT GSList
*
1431 nice_agent_poll_read (
1434 NiceAgentRecvFunc func
,
1444 g_static_rec_mutex_lock (&agent
->mutex
);
1448 for (i
= agent
->streams
; i
; i
= i
->next
)
1451 Stream
*stream
= i
->data
;
1453 for (k
= stream
->components
; k
; k
= k
->next
)
1455 Component
*component
= k
->data
;
1457 for (j
= component
->sockets
; j
; j
= j
->next
)
1459 NiceUDPSocket
*sockptr
= j
->data
;
1461 FD_SET (sockptr
->fileno
, &fds
);
1462 max_fd
= MAX (sockptr
->fileno
, max_fd
);
1467 for (i
= other_fds
; i
; i
= i
->next
)
1471 fileno
= GPOINTER_TO_UINT (i
->data
);
1472 FD_SET (fileno
, &fds
);
1473 max_fd
= MAX (fileno
, max_fd
);
1476 num_readable
= select (max_fd
+ 1, &fds
, NULL
, NULL
, NULL
);
1478 if (num_readable
< 1) {
1479 /* none readable, or error */
1483 for (j
= 0; j
<= max_fd
; j
++)
1484 if (FD_ISSET (j
, &fds
))
1486 if (g_slist_find (other_fds
, GUINT_TO_POINTER (j
))) {
1487 GSList
*modified_list
= g_slist_append (ret
, GUINT_TO_POINTER (j
));
1488 if (modified_list
== NULL
) {
1492 ret
= modified_list
;
1496 NiceUDPSocket
*socket
= NULL
;
1497 Stream
*stream
= NULL
;
1498 Component
*component
= NULL
;
1499 gchar buf
[MAX_BUFFER_SIZE
];
1502 for (i
= agent
->streams
; i
; i
= i
->next
)
1504 Stream
*s
= i
->data
;
1505 Component
*c
= stream_find_component_by_fd (s
, j
);
1507 socket
= component_find_udp_socket_by_fd (c
, j
);
1509 if (socket
!= NULL
) {
1516 if (socket
== NULL
|| stream
== NULL
|| component
== NULL
)
1519 len
= _nice_agent_recv (agent
, stream
, component
,
1520 socket
, MAX_BUFFER_SIZE
, buf
);
1522 if (len
&& func
!= NULL
)
1523 func (agent
, stream
->id
, component
->id
, len
, buf
,
1529 g_static_rec_mutex_unlock (&agent
->mutex
);
1536 * Sends a data payload over a stream component.
1538 * @pre component state MUST be NICE_COMPONENT_STATE_READY,
1539 * or as a special case, in any state if component was
1540 * in READY state before and was then restarted
1542 * @return number of bytes sent, or negative error code
1553 Component
*component
;
1556 g_static_rec_mutex_lock (&agent
->mutex
);
1558 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1562 if (component
->selected_pair
.local
!= NULL
)
1564 NiceUDPSocket
*sock
;
1568 gchar tmpbuf
[INET6_ADDRSTRLEN
];
1569 nice_address_to_string (&component
->selected_pair
.remote
->addr
, tmpbuf
);
1571 g_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", agent
, stream_id
, component_id
,
1573 nice_address_get_port (&component
->selected_pair
.remote
->addr
));
1576 sock
= component
->selected_pair
.local
->sockptr
;
1577 addr
= &component
->selected_pair
.remote
->addr
;
1578 nice_udp_socket_send (sock
, addr
, len
, buf
);
1579 component
->media_after_tick
= TRUE
;
1586 g_static_rec_mutex_unlock (&agent
->mutex
);
1592 * nice_agent_get_local_candidates:
1593 * @agent: A NiceAgent
1595 * The caller owns the returned GSList as well as the candidates contained
1596 * within it. To get full results, the client should wait for the
1597 * 'candidates-gathering-done' signal.
1599 * Returns: a GSList of local candidates (NiceCandidate) belonging to @agent
1601 NICEAPI_EXPORT GSList
*
1602 nice_agent_get_local_candidates (
1607 Component
*component
;
1608 GSList
* ret
= NULL
;
1609 GSList
* item
= NULL
;
1611 g_static_rec_mutex_lock (&agent
->mutex
);
1612 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
1617 for (item
= component
->local_candidates
; item
; item
= item
->next
)
1618 ret
= g_slist_append (ret
, nice_candidate_copy (item
->data
));
1621 g_static_rec_mutex_unlock (&agent
->mutex
);
1627 * nice_agent_get_remote_candidates:
1628 * @agent: A NiceAgent
1630 * The caller owns the returned GSList but not the candidates contained within
1633 * Note: the list of remote candidates can change during processing.
1634 * The client should register for the "new-remote-candidate" signal to
1635 * get notification of new remote candidates.
1637 * Returns: a GSList of remote candidates (NiceCandidate) belonging to @agent
1639 NICEAPI_EXPORT GSList
*
1640 nice_agent_get_remote_candidates (
1645 Component
*component
;
1646 GSList
*ret
= NULL
, *item
= NULL
;
1648 g_static_rec_mutex_lock (&agent
->mutex
);
1649 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
1654 for (item
= component
->remote_candidates
; item
; item
= item
->next
)
1655 ret
= g_slist_append (ret
, nice_candidate_copy (item
->data
));
1658 g_static_rec_mutex_unlock (&agent
->mutex
);
1663 * nice_agent_restart
1664 * @agent: A NiceAgent
1666 * Restarts the session as defined in ICE spec (ID-19). This function
1667 * needs to be called both when initiating (ICE spec section 9.1.1.1.
1668 * "ICE Restarts"), as well as when reacting (spec section 9.2.1.1.
1669 * "Detecting ICE Restart") to a restart.
1671 * Returns: FALSE on error
1674 nice_agent_restart (
1678 gboolean res
= TRUE
;
1680 g_static_rec_mutex_lock (&agent
->mutex
);
1682 /* step: clean up all connectivity checks */
1683 conn_check_free (agent
);
1685 /* step: regenerate tie-breaker value */
1686 priv_generate_tie_breaker (agent
);
1688 for (i
= agent
->streams
; i
&& res
; i
= i
->next
) {
1689 Stream
*stream
= i
->data
;
1691 /* step: reset local credentials for the stream and
1692 * clean up the list of remote candidates */
1693 res
= stream_restart (stream
, agent
->rng
);
1696 g_static_rec_mutex_unlock (&agent
->mutex
);
1701 nice_agent_dispose (GObject
*object
)
1704 NiceAgent
*agent
= NICE_AGENT (object
);
1706 /* step: free resources for the binding discovery timers */
1707 discovery_free (agent
);
1708 g_assert (agent
->discovery_list
== NULL
);
1710 /* step: free resources for the connectivity check timers */
1711 conn_check_free (agent
);
1713 priv_remove_keepalive_timer (agent
);
1715 for (i
= agent
->local_addresses
; i
; i
= i
->next
)
1717 NiceAddress
*a
= i
->data
;
1719 nice_address_free (a
);
1722 g_slist_free (agent
->local_addresses
);
1723 agent
->local_addresses
= NULL
;
1725 for (i
= agent
->streams
; i
; i
= i
->next
)
1727 Stream
*s
= i
->data
;
1732 g_slist_free (agent
->streams
);
1733 agent
->streams
= NULL
;
1735 g_free (agent
->stun_server_ip
);
1736 agent
->stun_server_ip
= NULL
;
1738 nice_rng_free (agent
->rng
);
1741 if (G_OBJECT_CLASS (nice_agent_parent_class
)->dispose
)
1742 G_OBJECT_CLASS (nice_agent_parent_class
)->dispose (object
);
1744 nice_udp_socket_factory_close (&agent
->udp_socket_factory
);
1746 nice_udp_socket_factory_close (&agent
->relay_socket_factory
);
1749 g_static_rec_mutex_free (&agent
->mutex
);
1753 typedef struct _IOCtx IOCtx
;
1759 Component
*component
;
1760 NiceUDPSocket
*socket
;
1768 Component
*component
,
1769 NiceUDPSocket
*socket
)
1773 ctx
= g_slice_new0 (IOCtx
);
1776 ctx
->stream
= stream
;
1777 ctx
->component
= component
;
1778 ctx
->socket
= socket
;
1785 io_ctx_free (IOCtx
*ctx
)
1787 g_slice_free (IOCtx
, ctx
);
1791 nice_agent_g_source_cb (
1794 GIOCondition condition
,
1797 /* return value is whether to keep the source */
1800 NiceAgent
*agent
= ctx
->agent
;
1801 Stream
*stream
= ctx
->stream
;
1802 Component
*component
= ctx
->component
;
1803 gchar buf
[MAX_BUFFER_SIZE
];
1806 g_static_rec_mutex_lock (&agent
->mutex
);
1808 /* note: dear compiler, these are for you: */
1811 len
= _nice_agent_recv (agent
, stream
, component
, ctx
->socket
,
1812 MAX_BUFFER_SIZE
, buf
);
1814 if (len
> 0 && component
->g_source_io_cb
)
1815 component
->g_source_io_cb (agent
, stream
->id
, component
->id
,
1816 len
, buf
, component
->data
);
1818 g_static_rec_mutex_unlock (&agent
->mutex
);
1823 * Attaches one socket handle to the main loop event context
1827 priv_attach_stream_component_socket (NiceAgent
*agent
,
1829 Component
*component
,
1830 NiceUDPSocket
*udp_socket
)
1836 if (!component
->ctx
)
1839 io
= g_io_channel_unix_new (udp_socket
->fileno
);
1840 /* note: without G_IO_ERR the glib mainloop goes into
1841 * busyloop if errors are encountered */
1842 source
= g_io_create_watch (io
, G_IO_IN
| G_IO_ERR
);
1843 ctx
= io_ctx_new (agent
, stream
, component
, udp_socket
);
1844 g_source_set_callback (source
, (GSourceFunc
) nice_agent_g_source_cb
,
1845 ctx
, (GDestroyNotify
) io_ctx_free
);
1846 g_debug ("Agent %p : Attach source %p (stream %u).", agent
, source
, stream
->id
);
1847 g_source_attach (source
, component
->ctx
);
1848 component
->gsources
= g_slist_append (component
->gsources
, source
);
1853 * Attaches socket handles of 'stream' to the main eventloop
1858 priv_attach_stream_component (NiceAgent
*agent
,
1860 Component
*component
)
1864 for (i
= component
->sockets
; i
; i
= i
->next
)
1865 priv_attach_stream_component_socket (agent
, stream
, component
, i
->data
);
1871 * Detaches socket handles of 'stream' from the main eventloop
1875 static void priv_detach_stream_component (Stream
*stream
, Component
*component
)
1879 for (i
= component
->gsources
; i
; i
= i
->next
) {
1880 GSource
*source
= i
->data
;
1881 g_debug ("Detach source %p (stream %u).", source
, stream
->id
);
1882 g_source_destroy (source
);
1885 g_slist_free (component
->gsources
);
1886 component
->gsources
= NULL
;
1889 NICEAPI_EXPORT gboolean
1890 nice_agent_attach_recv (
1895 NiceAgentRecvFunc func
,
1898 Component
*component
= NULL
;
1899 Stream
*stream
= NULL
;
1900 gboolean ret
= FALSE
;
1902 g_static_rec_mutex_lock (&agent
->mutex
);
1904 /* attach candidates */
1906 /* step: check that params specify an existing pair */
1907 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1908 g_warning ("Could not find component %u in stream %u", component_id
,
1913 if (component
->g_source_io_cb
&& func
== NULL
)
1914 priv_detach_stream_component (stream
, component
);
1919 component
->g_source_io_cb
= func
;
1920 component
->data
= data
;
1921 component
->ctx
= ctx
;
1922 priv_attach_stream_component (agent
, stream
, component
);
1924 component
->g_source_io_cb
= NULL
;
1925 component
->data
= NULL
;
1926 component
->ctx
= NULL
;
1931 g_static_rec_mutex_unlock (&agent
->mutex
);
1936 * Sets the selected candidate pair for media transmission
1937 * for given stream component. Calling this function will
1938 * disable all further ICE processing (connection check,
1939 * state machine updates, etc). Note that keepalives will
1940 * continue to be sent.
1942 NICEAPI_EXPORT gboolean
1943 nice_agent_set_selected_pair (
1947 const gchar
*lfoundation
,
1948 const gchar
*rfoundation
)
1950 Component
*component
;
1953 gboolean ret
= FALSE
;
1955 g_static_rec_mutex_lock (&agent
->mutex
);
1957 /* step: check that params specify an existing pair */
1958 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1962 if (!component_find_pair (component
, agent
, lfoundation
, rfoundation
, &pair
)){
1966 /* step: stop connectivity checks (note: for the whole stream) */
1967 conn_check_prune_stream (agent
, stream
);
1969 /* step: change component state */
1970 agent_signal_component_state_change (agent
, stream_id
, component_id
, NICE_COMPONENT_STATE_READY
);
1972 /* step: set the selected pair */
1973 component_update_selected_pair (component
, &pair
);
1974 agent_signal_new_selected_pair (agent
, stream_id
, component_id
, lfoundation
, rfoundation
);
1979 g_static_rec_mutex_unlock (&agent
->mutex
);
1984 guint
agent_timeout_add_with_context (NiceAgent
*agent
, guint interval
,
1985 GSourceFunc function
, gpointer data
)
1990 g_return_val_if_fail (function
!= NULL
, 0);
1992 source
= g_timeout_source_new (interval
);
1994 g_source_set_callback (source
, function
, data
, NULL
);
1995 id
= g_source_attach (source
, agent
->main_context
);
1996 g_source_unref (source
);
2003 * nice_agent_set_selected_remote_candidate:
2004 * @agent: a #NiceAgent
2005 * @stream_id: the stream id
2006 * @component_id: the component id
2007 * @candidate: the #NiceCandidate to force
2009 * Sets the selected remote candidate for media transmission
2010 * for given stream component. Calling this function will
2011 * disable all further ICE processing (connection check,
2012 * state machine updates, etc). Note that keepalives will
2013 * continue to be sent.
2015 * Returns: %TRUE on success, %FALSE on failure
2017 NICEAPI_EXPORT gboolean
2018 nice_agent_set_selected_remote_candidate (
2022 NiceCandidate
*candidate
)
2024 Component
*component
;
2026 NiceCandidate
*lcandidate
= NULL
;
2027 gboolean ret
= FALSE
;
2029 g_static_rec_mutex_lock (&agent
->mutex
);
2031 /* step: check if the component exists*/
2032 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
2036 /* step: stop connectivity checks (note: for the whole stream) */
2037 conn_check_prune_stream (agent
, stream
);
2040 /* step: set the selected pair */
2041 lcandidate
= component_set_selected_remote_candidate (agent
, component
,
2046 /* step: change component state */
2047 agent_signal_component_state_change (agent
, stream_id
, component_id
, NICE_COMPONENT_STATE_READY
);
2049 agent_signal_new_selected_pair (agent
, stream_id
, component_id
,
2050 lcandidate
->foundation
,
2051 candidate
->foundation
);
2056 g_static_rec_mutex_unlock (&agent
->mutex
);