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 * @pwd: NULL-terminated string containing an ICE password
1047 * @return TRUE on success
1049 NICEAPI_EXPORT gboolean
1050 nice_agent_set_remote_credentials (
1053 const gchar
*ufrag
, const gchar
*pwd
)
1056 gboolean ret
= FALSE
;
1058 g_static_rec_mutex_lock (&agent
->mutex
);
1060 stream
= agent_find_stream (agent
, stream_id
);
1061 /* note: oddly enough, ufrag and pwd can be empty strings */
1062 if (stream
&& ufrag
&& pwd
) {
1064 g_strlcpy (stream
->remote_ufrag
, ufrag
, NICE_STREAM_MAX_UFRAG
);
1065 g_strlcpy (stream
->remote_password
, pwd
, NICE_STREAM_MAX_PWD
);
1072 g_static_rec_mutex_unlock (&agent
->mutex
);
1077 * Gets the local credentials for stream 'stream_id'.
1079 * @agent: a NiceAgent
1080 * @stream_id: identifier returnedby nice_agent_add_stream()
1081 * @ufrag: a pointer to a NULL-terminated string containing
1082 * an ICE username fragment [OUT]
1083 * @pwd: a pointer to a NULL-terminated string containing an ICE
1086 * @return TRUE on success
1088 NICEAPI_EXPORT gboolean
1089 nice_agent_get_local_credentials (
1092 const gchar
**ufrag
, const gchar
**pwd
)
1095 gboolean ret
= TRUE
;
1097 g_static_rec_mutex_lock (&agent
->mutex
);
1099 stream
= agent_find_stream (agent
, stream_id
);
1100 if (stream
== NULL
) {
1104 if (!ufrag
|| !pwd
) {
1108 *ufrag
= stream
->local_ufrag
;
1109 *pwd
= stream
->local_password
;
1114 g_static_rec_mutex_unlock (&agent
->mutex
);
1119 * nice_agent_add_remote_candidate
1120 * @agent: a NiceAgent
1121 * @stream_id: the ID of the stream the candidate is for
1122 * @component_id: the ID of the component the candidate is for
1123 * @type: the type of the new candidate
1124 * @addr: the new candidate's IP address
1125 * @username: the new candidate's username (XXX: candidates don't have usernames)
1126 * @password: the new candidate's password (XXX: candidates don't have usernames)
1128 * Add a candidate our peer has informed us about to the agent's list.
1130 * Note: NICE_AGENT_MAX_REMOTE_CANDIDATES is the absolute
1131 * maximum limit for remote candidates
1132 * @return FALSE on fatal (memory alloc) errors
1134 NICEAPI_EXPORT gboolean
1135 nice_agent_add_remote_candidate (
1139 NiceCandidateType type
,
1141 const gchar
*username
,
1142 const gchar
*password
)
1145 /* XXX: to be deprecated */
1147 g_static_rec_mutex_lock (&agent
->mutex
);
1149 /* XXX: should we allow use of this method without an
1150 * initial call to nice_agent_set_remote_candidates()
1151 * with an empty set? */
1154 priv_add_remote_candidate (agent
,
1160 NICE_CANDIDATE_TRANSPORT_UDP
,
1166 /* XXX/later: for each component, generate a new check with the new
1167 candidate, see below set_remote_candidates() */
1170 g_static_rec_mutex_unlock (&agent
->mutex
);
1175 * nice_agent_set_remote_candidates
1176 * @agent: a NiceAgent
1177 * @stream_id: the ID of the stream the candidate is for
1178 * @component_id: the ID of the component the candidate is for
1179 * @candidates: a list of NiceCandidate items describing the candidates
1181 * Sets the remote candidates for a component of a stream. Replaces
1182 * any existing remote candidates.
1184 * Note: NICE_AGENT_MAX_REMOTE_CANDIDATES is the absolute
1185 * maximum limit for remote candidates
1187 * @return number of candidates added, negative on fatal (memory
1191 nice_agent_set_remote_candidates (NiceAgent
*agent
, guint stream_id
, guint component_id
, const GSList
*candidates
)
1197 if (agent
->discovery_unsched_items
> 0)
1200 g_static_rec_mutex_lock (&agent
->mutex
);
1202 for (i
= candidates
; i
&& added
>= 0; i
= i
->next
) {
1203 NiceCandidate
*d
= (NiceCandidate
*) i
->data
;
1205 priv_add_remote_candidate (agent
,
1222 conn_check_remote_candidates_set(agent
);
1225 gboolean res
= conn_check_schedule_next (agent
);
1227 g_debug ("Agent %p : Warning: unable to schedule any conn checks!", agent
);
1230 g_static_rec_mutex_unlock (&agent
->mutex
);
1236 * Reads data from a ready, nonblocking socket attached to an ICE
1239 * @return number of octets received, or negative on error
1245 Component
*component
,
1246 NiceUDPSocket
*udp_socket
,
1253 len
= nice_udp_socket_recv (udp_socket
, &from
,
1258 gchar tmpbuf
[INET6_ADDRSTRLEN
];
1259 nice_address_to_string (&from
, tmpbuf
);
1260 g_debug ("Agent %p : Packet received on local socket %u from [%s]:%u (%u octets).", agent
,
1261 udp_socket
->fileno
, tmpbuf
, nice_address_get_port (&from
), len
);
1268 if ((guint
)len
> buf_len
)
1270 /* buffer is not big enough to accept this packet */
1271 /* XXX: test this case */
1275 if (nice_address_equal (&from
, &component
->turn_server
)) {
1277 g_debug ("Agent %p : Packet received from TURN server candidate.", agent
);
1278 for (i
= component
->local_candidates
; i
; i
= i
->next
) {
1279 NiceCandidate
*cand
= i
->data
;
1280 if (cand
->type
== NICE_CANDIDATE_TYPE_RELAYED
) {
1281 len
= nice_udp_turn_socket_parse_recv (cand
->sockptr
, &from
, len
, buf
, &from
, buf
, len
);
1286 if (stun_message_validate_buffer_length ((uint8_t *) buf
, (size_t) len
) == len
) {
1287 /* If the retval is no 0, its not a valid stun packet, probably data */
1288 if (conn_check_handle_inbound_stun (agent
, stream
, component
, udp_socket
,
1289 &from
, buf
, len
) == FALSE
) {
1290 /* unhandled STUN, pass to client */
1294 /* not STUN, pass to client */
1298 /* handled STUN message*/
1304 * @agent: a NiceAgent
1305 * @stream_id: the ID of the stream to recieve data from
1306 * @component_id: the ID of the component to receive data from
1307 * @buf_len: the size of @buf
1308 * @buf: the buffer to read data into
1310 * Receive data on a particular component.
1312 * Returns: the amount of data read into @buf
1314 NICEAPI_EXPORT guint
1328 Component
*component
;
1331 g_static_rec_mutex_lock (&agent
->mutex
);
1332 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1338 for (i
= component
->sockets
; i
; i
= i
->next
)
1340 NiceUDPSocket
*sockptr
= i
->data
;
1342 FD_SET (sockptr
->fileno
, &fds
);
1343 max_fd
= MAX (sockptr
->fileno
, max_fd
);
1346 /* Loop on candidate sockets until we find one that has non-STUN data
1352 num_readable
= select (max_fd
+ 1, &fds
, NULL
, NULL
, NULL
);
1353 g_assert (num_readable
>= 0);
1355 if (num_readable
> 0)
1359 for (j
= 0; j
<= max_fd
; j
++)
1360 if (FD_ISSET (j
, &fds
))
1362 NiceUDPSocket
*socket
;
1364 socket
= component_find_udp_socket_by_fd (component
, j
);
1367 len
= _nice_agent_recv (agent
, stream
, component
, socket
,
1378 /* note: commented out to avoid compiler warnings
1380 * g_assert_not_reached (); */
1382 g_static_rec_mutex_unlock (&agent
->mutex
);
1386 NICEAPI_EXPORT guint
1387 nice_agent_recv_sock (
1395 NiceUDPSocket
*socket
;
1397 Component
*component
;
1400 g_static_rec_mutex_lock (&agent
->mutex
);
1401 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1405 socket
= component_find_udp_socket_by_fd (component
, sock
);
1408 ret
= _nice_agent_recv (agent
, stream
, component
,
1409 socket
, buf_len
, buf
);
1412 g_static_rec_mutex_unlock (&agent
->mutex
);
1418 * nice_agent_poll_read:
1419 * @agent: A NiceAgent
1420 * @other_fds: A GSList of other file descriptors to poll
1422 * Polls the agent's sockets until at least one of them is readable, and
1423 * additionally if @other_fds is not NULL, polls those for readability too.
1424 * @other_fds should contain the file descriptors directly, i.e. using
1427 * Returns: A list of file descriptors from @other_fds that are readable
1429 NICEAPI_EXPORT GSList
*
1430 nice_agent_poll_read (
1433 NiceAgentRecvFunc func
,
1443 g_static_rec_mutex_lock (&agent
->mutex
);
1447 for (i
= agent
->streams
; i
; i
= i
->next
)
1450 Stream
*stream
= i
->data
;
1452 for (k
= stream
->components
; k
; k
= k
->next
)
1454 Component
*component
= k
->data
;
1456 for (j
= component
->sockets
; j
; j
= j
->next
)
1458 NiceUDPSocket
*sockptr
= j
->data
;
1460 FD_SET (sockptr
->fileno
, &fds
);
1461 max_fd
= MAX (sockptr
->fileno
, max_fd
);
1466 for (i
= other_fds
; i
; i
= i
->next
)
1470 fileno
= GPOINTER_TO_UINT (i
->data
);
1471 FD_SET (fileno
, &fds
);
1472 max_fd
= MAX (fileno
, max_fd
);
1475 num_readable
= select (max_fd
+ 1, &fds
, NULL
, NULL
, NULL
);
1477 if (num_readable
< 1) {
1478 /* none readable, or error */
1482 for (j
= 0; j
<= max_fd
; j
++)
1483 if (FD_ISSET (j
, &fds
))
1485 if (g_slist_find (other_fds
, GUINT_TO_POINTER (j
))) {
1486 GSList
*modified_list
= g_slist_append (ret
, GUINT_TO_POINTER (j
));
1487 if (modified_list
== NULL
) {
1491 ret
= modified_list
;
1495 NiceUDPSocket
*socket
= NULL
;
1496 Stream
*stream
= NULL
;
1497 Component
*component
= NULL
;
1498 gchar buf
[MAX_BUFFER_SIZE
];
1501 for (i
= agent
->streams
; i
; i
= i
->next
)
1503 Stream
*s
= i
->data
;
1504 Component
*c
= stream_find_component_by_fd (s
, j
);
1506 socket
= component_find_udp_socket_by_fd (c
, j
);
1508 if (socket
!= NULL
) {
1515 if (socket
== NULL
|| stream
== NULL
|| component
== NULL
)
1518 len
= _nice_agent_recv (agent
, stream
, component
,
1519 socket
, MAX_BUFFER_SIZE
, buf
);
1521 if (len
&& func
!= NULL
)
1522 func (agent
, stream
->id
, component
->id
, len
, buf
,
1528 g_static_rec_mutex_unlock (&agent
->mutex
);
1535 * Sends a data payload over a stream component.
1537 * @pre component state MUST be NICE_COMPONENT_STATE_READY,
1538 * or as a special case, in any state if component was
1539 * in READY state before and was then restarted
1541 * @return number of bytes sent, or negative error code
1552 Component
*component
;
1555 g_static_rec_mutex_lock (&agent
->mutex
);
1557 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1561 if (component
->selected_pair
.local
!= NULL
)
1563 NiceUDPSocket
*sock
;
1567 gchar tmpbuf
[INET6_ADDRSTRLEN
];
1568 nice_address_to_string (&component
->selected_pair
.remote
->addr
, tmpbuf
);
1570 g_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", agent
, stream_id
, component_id
,
1572 nice_address_get_port (&component
->selected_pair
.remote
->addr
));
1575 sock
= component
->selected_pair
.local
->sockptr
;
1576 addr
= &component
->selected_pair
.remote
->addr
;
1577 nice_udp_socket_send (sock
, addr
, len
, buf
);
1578 component
->media_after_tick
= TRUE
;
1585 g_static_rec_mutex_unlock (&agent
->mutex
);
1591 * nice_agent_get_local_candidates:
1592 * @agent: A NiceAgent
1594 * The caller owns the returned GSList but not the candidates contained within
1595 * it. To get full results, the client should wait for the
1596 * 'candidates-gathering-done' signal.
1598 * Returns: a GSList of local candidates (NiceCandidate) belonging to @agent
1600 NICEAPI_EXPORT GSList
*
1601 nice_agent_get_local_candidates (
1606 Component
*component
;
1607 GSList
* ret
= NULL
;
1608 GSList
* item
= NULL
;
1610 g_static_rec_mutex_lock (&agent
->mutex
);
1611 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
1616 for (item
= component
->local_candidates
; item
; item
= item
->next
)
1617 ret
= g_slist_append (ret
, nice_candidate_copy (item
->data
));
1620 g_static_rec_mutex_unlock (&agent
->mutex
);
1626 * nice_agent_get_remote_candidates:
1627 * @agent: A NiceAgent
1629 * The caller owns the returned GSList but not the candidates contained within
1632 * Note: the list of remote candidates can change during processing.
1633 * The client should register for the "new-remote-candidate" signal to
1634 * get notification of new remote candidates.
1636 * Returns: a GSList of remote candidates (NiceCandidate) belonging to @agent
1638 NICEAPI_EXPORT GSList
*
1639 nice_agent_get_remote_candidates (
1644 Component
*component
;
1645 GSList
*ret
= NULL
, *item
= NULL
;
1647 g_static_rec_mutex_lock (&agent
->mutex
);
1648 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
1653 for (item
= component
->remote_candidates
; item
; item
= item
->next
)
1654 ret
= g_slist_append (ret
, nice_candidate_copy (item
->data
));
1657 g_static_rec_mutex_unlock (&agent
->mutex
);
1662 * nice_agent_restart
1663 * @agent: A NiceAgent
1665 * Restarts the session as defined in ICE spec (ID-19). This function
1666 * needs to be called both when initiating (ICE spec section 9.1.1.1.
1667 * "ICE Restarts"), as well as when reacting (spec section 9.2.1.1.
1668 * "Detecting ICE Restart") to a restart.
1670 * Returns: FALSE on error
1673 nice_agent_restart (
1677 gboolean res
= TRUE
;
1679 g_static_rec_mutex_lock (&agent
->mutex
);
1681 /* step: clean up all connectivity checks */
1682 conn_check_free (agent
);
1684 /* step: regenerate tie-breaker value */
1685 priv_generate_tie_breaker (agent
);
1687 for (i
= agent
->streams
; i
&& res
; i
= i
->next
) {
1688 Stream
*stream
= i
->data
;
1690 /* step: reset local credentials for the stream and
1691 * clean up the list of remote candidates */
1692 res
= stream_restart (stream
, agent
->rng
);
1695 g_static_rec_mutex_unlock (&agent
->mutex
);
1700 nice_agent_dispose (GObject
*object
)
1703 NiceAgent
*agent
= NICE_AGENT (object
);
1705 /* step: free resources for the binding discovery timers */
1706 discovery_free (agent
);
1707 g_assert (agent
->discovery_list
== NULL
);
1709 /* step: free resources for the connectivity check timers */
1710 conn_check_free (agent
);
1712 priv_remove_keepalive_timer (agent
);
1714 for (i
= agent
->local_addresses
; i
; i
= i
->next
)
1716 NiceAddress
*a
= i
->data
;
1718 nice_address_free (a
);
1721 g_slist_free (agent
->local_addresses
);
1722 agent
->local_addresses
= NULL
;
1724 for (i
= agent
->streams
; i
; i
= i
->next
)
1726 Stream
*s
= i
->data
;
1731 g_slist_free (agent
->streams
);
1732 agent
->streams
= NULL
;
1734 g_free (agent
->stun_server_ip
);
1735 agent
->stun_server_ip
= NULL
;
1737 nice_rng_free (agent
->rng
);
1740 if (G_OBJECT_CLASS (nice_agent_parent_class
)->dispose
)
1741 G_OBJECT_CLASS (nice_agent_parent_class
)->dispose (object
);
1743 nice_udp_socket_factory_close (&agent
->udp_socket_factory
);
1745 nice_udp_socket_factory_close (&agent
->relay_socket_factory
);
1748 g_static_rec_mutex_free (&agent
->mutex
);
1752 typedef struct _IOCtx IOCtx
;
1758 Component
*component
;
1759 NiceUDPSocket
*socket
;
1767 Component
*component
,
1768 NiceUDPSocket
*socket
)
1772 ctx
= g_slice_new0 (IOCtx
);
1775 ctx
->stream
= stream
;
1776 ctx
->component
= component
;
1777 ctx
->socket
= socket
;
1784 io_ctx_free (IOCtx
*ctx
)
1786 g_slice_free (IOCtx
, ctx
);
1790 nice_agent_g_source_cb (
1793 GIOCondition condition
,
1796 /* return value is whether to keep the source */
1799 NiceAgent
*agent
= ctx
->agent
;
1800 Stream
*stream
= ctx
->stream
;
1801 Component
*component
= ctx
->component
;
1802 gchar buf
[MAX_BUFFER_SIZE
];
1805 g_static_rec_mutex_lock (&agent
->mutex
);
1807 /* note: dear compiler, these are for you: */
1810 len
= _nice_agent_recv (agent
, stream
, component
, ctx
->socket
,
1811 MAX_BUFFER_SIZE
, buf
);
1813 if (len
> 0 && component
->g_source_io_cb
)
1814 component
->g_source_io_cb (agent
, stream
->id
, component
->id
,
1815 len
, buf
, component
->data
);
1817 g_static_rec_mutex_unlock (&agent
->mutex
);
1822 * Attaches one socket handle to the main loop event context
1826 priv_attach_stream_component_socket (NiceAgent
*agent
,
1828 Component
*component
,
1829 NiceUDPSocket
*udp_socket
)
1835 if (!component
->ctx
)
1838 io
= g_io_channel_unix_new (udp_socket
->fileno
);
1839 /* note: without G_IO_ERR the glib mainloop goes into
1840 * busyloop if errors are encountered */
1841 source
= g_io_create_watch (io
, G_IO_IN
| G_IO_ERR
);
1842 ctx
= io_ctx_new (agent
, stream
, component
, udp_socket
);
1843 g_source_set_callback (source
, (GSourceFunc
) nice_agent_g_source_cb
,
1844 ctx
, (GDestroyNotify
) io_ctx_free
);
1845 g_debug ("Agent %p : Attach source %p (stream %u).", agent
, source
, stream
->id
);
1846 g_source_attach (source
, component
->ctx
);
1847 component
->gsources
= g_slist_append (component
->gsources
, source
);
1852 * Attaches socket handles of 'stream' to the main eventloop
1857 priv_attach_stream_component (NiceAgent
*agent
,
1859 Component
*component
)
1863 for (i
= component
->sockets
; i
; i
= i
->next
)
1864 priv_attach_stream_component_socket (agent
, stream
, component
, i
->data
);
1870 * Detaches socket handles of 'stream' from the main eventloop
1874 static void priv_detach_stream_component (Stream
*stream
, Component
*component
)
1878 for (i
= component
->gsources
; i
; i
= i
->next
) {
1879 GSource
*source
= i
->data
;
1880 g_debug ("Detach source %p (stream %u).", source
, stream
->id
);
1881 g_source_destroy (source
);
1884 g_slist_free (component
->gsources
);
1885 component
->gsources
= NULL
;
1888 NICEAPI_EXPORT gboolean
1889 nice_agent_attach_recv (
1894 NiceAgentRecvFunc func
,
1897 Component
*component
= NULL
;
1898 Stream
*stream
= NULL
;
1899 gboolean ret
= FALSE
;
1901 g_static_rec_mutex_lock (&agent
->mutex
);
1903 /* attach candidates */
1905 /* step: check that params specify an existing pair */
1906 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1907 g_warning ("Could not find component %u in stream %u", component_id
,
1912 if (component
->g_source_io_cb
&& func
== NULL
)
1913 priv_detach_stream_component (stream
, component
);
1918 component
->g_source_io_cb
= func
;
1919 component
->data
= data
;
1920 component
->ctx
= ctx
;
1921 priv_attach_stream_component (agent
, stream
, component
);
1923 component
->g_source_io_cb
= NULL
;
1924 component
->data
= NULL
;
1925 component
->ctx
= NULL
;
1930 g_static_rec_mutex_unlock (&agent
->mutex
);
1935 * Sets the selected candidate pair for media transmission
1936 * for given stream component. Calling this function will
1937 * disable all further ICE processing (connection check,
1938 * state machine updates, etc). Note that keepalives will
1939 * continue to be sent.
1941 NICEAPI_EXPORT gboolean
1942 nice_agent_set_selected_pair (
1946 const gchar
*lfoundation
,
1947 const gchar
*rfoundation
)
1949 Component
*component
;
1952 gboolean ret
= FALSE
;
1954 g_static_rec_mutex_lock (&agent
->mutex
);
1956 /* step: check that params specify an existing pair */
1957 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1961 if (!component_find_pair (component
, agent
, lfoundation
, rfoundation
, &pair
)){
1965 /* step: stop connectivity checks (note: for the whole stream) */
1966 conn_check_prune_stream (agent
, stream
);
1968 /* step: change component state */
1969 agent_signal_component_state_change (agent
, stream_id
, component_id
, NICE_COMPONENT_STATE_READY
);
1971 /* step: set the selected pair */
1972 component_update_selected_pair (component
, &pair
);
1973 agent_signal_new_selected_pair (agent
, stream_id
, component_id
, lfoundation
, rfoundation
);
1978 g_static_rec_mutex_unlock (&agent
->mutex
);
1983 guint
agent_timeout_add_with_context (NiceAgent
*agent
, guint interval
,
1984 GSourceFunc function
, gpointer data
)
1989 g_return_val_if_fail (function
!= NULL
, 0);
1991 source
= g_timeout_source_new (interval
);
1993 g_source_set_callback (source
, function
, data
, NULL
);
1994 id
= g_source_attach (source
, agent
->main_context
);
1995 g_source_unref (source
);
2002 * nice_agent_set_selected_remote_candidate:
2003 * @agent: a #NiceAgent
2004 * @stream_id: the stream id
2005 * @component_id: the component id
2006 * @candidate: the #NiceCandidate to force
2008 * Sets the selected remote candidate for media transmission
2009 * for given stream component. Calling this function will
2010 * disable all further ICE processing (connection check,
2011 * state machine updates, etc). Note that keepalives will
2012 * continue to be sent.
2014 * Returns: %TRUE on success, %FALSE on failure
2016 NICEAPI_EXPORT gboolean
2017 nice_agent_set_selected_remote_candidate (
2021 NiceCandidate
*candidate
)
2023 Component
*component
;
2025 NiceCandidate
*lcandidate
= NULL
;
2026 gboolean ret
= FALSE
;
2028 g_static_rec_mutex_lock (&agent
->mutex
);
2030 /* step: check if the component exists*/
2031 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
2035 /* step: stop connectivity checks (note: for the whole stream) */
2036 conn_check_prune_stream (agent
, stream
);
2039 /* step: set the selected pair */
2040 lcandidate
= component_set_selected_remote_candidate (agent
, component
,
2045 /* step: change component state */
2046 agent_signal_component_state_change (agent
, stream_id
, component_id
, NICE_COMPONENT_STATE_READY
);
2048 agent_signal_new_selected_pair (agent
, stream_id
, component_id
,
2049 lcandidate
->foundation
,
2050 candidate
->foundation
);
2055 g_static_rec_mutex_unlock (&agent
->mutex
);