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.
43 #define NICEAPI_EXPORT
54 #include <sys/socket.h>
55 #include <netinet/in.h>
56 #include <arpa/inet.h>
62 #include "stun/usages/turn.h"
63 #include "candidate.h"
64 #include "component.h"
65 #include "conncheck.h"
66 #include "discovery.h"
68 #include "agent-priv.h"
69 #include "agent-signals-marshal.h"
72 #include "interfaces.h"
74 /* This is the max size of a UDP packet
75 * will it work tcp relaying??
77 #define MAX_BUFFER_SIZE 65536
78 #define DEFAULT_STUN_PORT 3478
81 G_DEFINE_TYPE (NiceAgent
, nice_agent
, G_TYPE_OBJECT
);
85 PROP_COMPATIBILITY
= 1,
88 PROP_STUN_SERVER_PORT
,
89 PROP_CONTROLLING_MODE
,
91 PROP_STUN_PACING_TIMER
,
92 PROP_MAX_CONNECTIVITY_CHECKS
,
103 SIGNAL_COMPONENT_STATE_CHANGED
,
104 SIGNAL_CANDIDATE_GATHERING_DONE
,
105 SIGNAL_NEW_SELECTED_PAIR
,
106 SIGNAL_NEW_CANDIDATE
,
107 SIGNAL_NEW_REMOTE_CANDIDATE
,
108 SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED
,
112 static guint signals
[N_SIGNALS
];
114 static gboolean
priv_attach_stream_component (NiceAgent
*agent
,
116 Component
*component
);
117 static void priv_detach_stream_component (Stream
*stream
, Component
*component
);
119 StunUsageIceCompatibility
120 agent_to_ice_compatibility (NiceAgent
*agent
)
122 return agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
?
123 STUN_USAGE_ICE_COMPATIBILITY_GOOGLE
:
124 agent
->compatibility
== NICE_COMPATIBILITY_MSN
?
125 STUN_USAGE_ICE_COMPATIBILITY_MSN
:
126 STUN_USAGE_ICE_COMPATIBILITY_DRAFT19
;
130 StunUsageTurnCompatibility
131 agent_to_turn_compatibility (NiceAgent
*agent
)
133 return agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
?
134 STUN_USAGE_TURN_COMPATIBILITY_GOOGLE
:
135 agent
->compatibility
== NICE_COMPATIBILITY_MSN
?
136 STUN_USAGE_TURN_COMPATIBILITY_MSN
:
137 agent
->compatibility
== NICE_COMPATIBILITY_WLM2009
?
138 STUN_USAGE_TURN_COMPATIBILITY_MSN
: STUN_USAGE_TURN_COMPATIBILITY_DRAFT9
;
141 NiceTurnSocketCompatibility
142 agent_to_turn_socket_compatibility (NiceAgent
*agent
)
144 return agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
?
145 NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE
:
146 agent
->compatibility
== NICE_COMPATIBILITY_MSN
?
147 NICE_TURN_SOCKET_COMPATIBILITY_MSN
:
148 agent
->compatibility
== NICE_COMPATIBILITY_WLM2009
?
149 NICE_TURN_SOCKET_COMPATIBILITY_MSN
:
150 NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9
;
153 Stream
*agent_find_stream (NiceAgent
*agent
, guint stream_id
)
157 for (i
= agent
->streams
; i
; i
= i
->next
)
161 if (s
->id
== stream_id
)
170 agent_find_component (
175 Component
**component
)
180 s
= agent_find_stream (agent
, stream_id
);
185 c
= stream_find_component_by_id (s
, component_id
);
201 nice_agent_dispose (GObject
*object
);
204 nice_agent_get_property (
211 nice_agent_set_property (
219 nice_agent_class_init (NiceAgentClass
*klass
)
221 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
223 gobject_class
->get_property
= nice_agent_get_property
;
224 gobject_class
->set_property
= nice_agent_set_property
;
225 gobject_class
->dispose
= nice_agent_dispose
;
227 /* install properties */
229 * NiceAgent:main-context:
231 * A GLib main context is needed for all timeouts used by libnice.
232 * This is a property being set by the nice_agent_new() call.
234 g_object_class_install_property (gobject_class
, PROP_MAIN_CONTEXT
,
235 g_param_spec_pointer (
237 "The GMainContext to use for timeouts",
238 "The GMainContext to use for timeouts",
239 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
242 * NiceAgent:compatibility:
244 * The Nice agent can work in various compatibility modes depending on
245 * what the application/peer needs.
246 * <para> See also: #NiceCompatibility</para>
248 g_object_class_install_property (gobject_class
, PROP_COMPATIBILITY
,
251 "ICE specification compatibility",
252 "The compatibility mode for the agent",
253 NICE_COMPATIBILITY_DRAFT19
, NICE_COMPATIBILITY_LAST
,
254 NICE_COMPATIBILITY_DRAFT19
,
255 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
257 g_object_class_install_property (gobject_class
, PROP_STUN_SERVER
,
258 g_param_spec_string (
261 "The STUN server used to obtain server-reflexive candidates",
265 g_object_class_install_property (gobject_class
, PROP_STUN_SERVER_PORT
,
269 "The STUN server used to obtain server-reflexive candidates",
271 1, /* not a construct property, ignored */
274 g_object_class_install_property (gobject_class
, PROP_CONTROLLING_MODE
,
275 g_param_spec_boolean (
277 "ICE controlling mode",
278 "Whether the agent is in controlling mode",
279 FALSE
, /* not a construct property, ignored */
282 g_object_class_install_property (gobject_class
, PROP_FULL_MODE
,
283 g_param_spec_boolean (
286 "Whether agent runs in ICE full mode",
287 TRUE
, /* use full mode by default */
288 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
290 g_object_class_install_property (gobject_class
, PROP_STUN_PACING_TIMER
,
294 "Timer 'Ta' (msecs) used in the IETF ICE specification for pacing candidate gathering and sending of connectivity checks",
296 NICE_AGENT_TIMER_TA_DEFAULT
,
297 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
299 /* note: according to spec recommendation in sect 5.7.3 (ID-19) */
300 g_object_class_install_property (gobject_class
, PROP_MAX_CONNECTIVITY_CHECKS
,
302 "max-connectivity-checks",
303 "Maximum number of connectivity checks",
304 "Upper limit for the total number of connectivity checks performed",
306 0, /* default set in init */
309 g_object_class_install_property (gobject_class
, PROP_PROXY_IP
,
310 g_param_spec_string (
313 "The proxy server used to bypass a proxy firewall",
317 g_object_class_install_property (gobject_class
, PROP_PROXY_PORT
,
321 "The Proxy server used to bypass a proxy firewall",
326 g_object_class_install_property (gobject_class
, PROP_PROXY_TYPE
,
329 "Type of proxy to use",
330 "The type of proxy set in the proxy-ip property",
331 NICE_PROXY_TYPE_NONE
, NICE_PROXY_TYPE_LAST
,
332 NICE_PROXY_TYPE_NONE
,
335 g_object_class_install_property (gobject_class
, PROP_PROXY_USERNAME
,
336 g_param_spec_string (
338 "Proxy server username",
339 "The username used to authenticate with the proxy",
343 g_object_class_install_property (gobject_class
, PROP_PROXY_PASSWORD
,
344 g_param_spec_string (
346 "Proxy server password",
347 "The password used to authenticate with the proxy",
351 /* install signals */
354 * NiceAgent::component-state-changed
355 * @stream_id: The ID of the stream
356 * @component_id: The ID of the component
357 * @state: The #NiceComponentState of the component
359 * This signal is fired whenever a component's state changes
361 signals
[SIGNAL_COMPONENT_STATE_CHANGED
] =
363 "component-state-changed",
364 G_OBJECT_CLASS_TYPE (klass
),
369 agent_marshal_VOID__UINT_UINT_UINT
,
372 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_UINT
,
376 * NiceAgent::candidate-gathering-done:
377 * @stream_id: The ID of the stream
379 * This signal is fired whenever a stream has finished gathering its
380 * candidates after a call to nice_agent_gather_candidates()
382 signals
[SIGNAL_CANDIDATE_GATHERING_DONE
] =
384 "candidate-gathering-done",
385 G_OBJECT_CLASS_TYPE (klass
),
390 agent_marshal_VOID__UINT
,
393 G_TYPE_UINT
, G_TYPE_INVALID
);
396 * NiceAgent::new-selected-pair
397 * @stream_id: The ID of the stream
398 * @component_id: The ID of the component
399 * @lfoundation: The local foundation of the selected candidate pair
400 * @rfoundation: The remote foundation of the selected candidate pair
402 * This signal is fired once a candidate pair is selected for data transfer for
403 * a stream's component
405 signals
[SIGNAL_NEW_SELECTED_PAIR
] =
408 G_OBJECT_CLASS_TYPE (klass
),
413 agent_marshal_VOID__UINT_UINT_STRING_STRING
,
416 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_STRING
, G_TYPE_STRING
,
420 * NiceAgent::new-candidate
421 * @stream_id: The ID of the stream
422 * @component_id: The ID of the component
423 * @foundation: The foundation of the new candidate
425 * This signal is fired when the agent discovers a new candidate
426 * <para> See also: #NiceAgent::candidates-gathering-done </para>
428 signals
[SIGNAL_NEW_CANDIDATE
] =
431 G_OBJECT_CLASS_TYPE (klass
),
436 agent_marshal_VOID__UINT_UINT_STRING
,
439 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_STRING
,
443 * NiceAgent::new-remote-candidate
444 * @stream_id: The ID of the stream
445 * @component_id: The ID of the component
446 * @foundation: The foundation of the new candidate
448 * This signal is fired when the agent discovers a new remote candidate.
449 * This can happen with peer reflexive candidates.
450 * <para> See also: #NiceAgent::candidates-gathering-done </para>
452 signals
[SIGNAL_NEW_REMOTE_CANDIDATE
] =
454 "new-remote-candidate",
455 G_OBJECT_CLASS_TYPE (klass
),
460 agent_marshal_VOID__UINT_UINT_STRING
,
463 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_STRING
,
467 * NiceAgent::initial-binding-request-received
468 * @stream_id: The ID of the stream
470 * This signal is fired when we received our first binding request from
473 signals
[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED
] =
475 "initial-binding-request-received",
476 G_OBJECT_CLASS_TYPE (klass
),
481 agent_marshal_VOID__UINT
,
487 /* Init debug options depending on env variables */
491 static void priv_generate_tie_breaker (NiceAgent
*agent
)
493 nice_rng_generate_bytes (agent
->rng
, 8, (gchar
*)&agent
->tie_breaker
);
497 nice_agent_init (NiceAgent
*agent
)
499 agent
->next_candidate_id
= 1;
500 agent
->next_stream_id
= 1;
502 /* set defaults; not construct params, so set here */
503 agent
->stun_server_port
= DEFAULT_STUN_PORT
;
504 agent
->controlling_mode
= TRUE
;
505 agent
->max_conn_checks
= NICE_AGENT_MAX_CONNECTIVITY_CHECKS_DEFAULT
;
507 agent
->discovery_list
= NULL
;
508 agent
->discovery_unsched_items
= 0;
509 agent
->discovery_timer_source
= NULL
;
510 agent
->conncheck_timer_source
= NULL
;
511 agent
->keepalive_timer_source
= NULL
;
512 agent
->refresh_list
= NULL
;
514 agent
->compatibility
= NICE_COMPATIBILITY_DRAFT19
;
516 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
517 STUN_COMPATIBILITY_RFC5389
,
518 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
519 STUN_AGENT_USAGE_USE_FINGERPRINT
);
521 agent
->rng
= nice_rng_new ();
522 priv_generate_tie_breaker (agent
);
524 g_static_rec_mutex_init (&agent
->mutex
);
528 NICEAPI_EXPORT NiceAgent
*
529 nice_agent_new (GMainContext
*ctx
, NiceCompatibility compat
)
531 NiceAgent
*agent
= g_object_new (NICE_TYPE_AGENT
,
532 "compatibility", compat
,
541 nice_agent_get_property (
547 NiceAgent
*agent
= NICE_AGENT (object
);
549 g_static_rec_mutex_lock (&agent
->mutex
);
553 case PROP_MAIN_CONTEXT
:
554 g_value_set_pointer (value
, agent
->main_context
);
557 case PROP_COMPATIBILITY
:
558 g_value_set_uint (value
, agent
->compatibility
);
561 case PROP_STUN_SERVER
:
562 g_value_set_string (value
, agent
->stun_server_ip
);
565 case PROP_STUN_SERVER_PORT
:
566 g_value_set_uint (value
, agent
->stun_server_port
);
569 case PROP_CONTROLLING_MODE
:
570 g_value_set_boolean (value
, agent
->controlling_mode
);
574 g_value_set_boolean (value
, agent
->full_mode
);
577 case PROP_STUN_PACING_TIMER
:
578 g_value_set_uint (value
, agent
->timer_ta
);
581 case PROP_MAX_CONNECTIVITY_CHECKS
:
582 g_value_set_uint (value
, agent
->max_conn_checks
);
583 /* XXX: should we prune the list of already existing checks? */
587 g_value_set_string (value
, agent
->proxy_ip
);
590 case PROP_PROXY_PORT
:
591 g_value_set_uint (value
, agent
->proxy_port
);
594 case PROP_PROXY_TYPE
:
595 g_value_set_uint (value
, agent
->proxy_type
);
598 case PROP_PROXY_USERNAME
:
599 g_value_set_string (value
, agent
->proxy_username
);
602 case PROP_PROXY_PASSWORD
:
603 g_value_set_string (value
, agent
->proxy_password
);
607 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
610 g_static_rec_mutex_unlock (&agent
->mutex
);
615 nice_agent_set_property (
621 NiceAgent
*agent
= NICE_AGENT (object
);
623 g_static_rec_mutex_lock (&agent
->mutex
);
627 case PROP_MAIN_CONTEXT
:
628 agent
->main_context
= g_value_get_pointer (value
);
631 case PROP_COMPATIBILITY
:
632 agent
->compatibility
= g_value_get_uint (value
);
633 if (agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
) {
634 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
635 STUN_COMPATIBILITY_RFC3489
,
636 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
637 STUN_AGENT_USAGE_IGNORE_CREDENTIALS
);
638 } else if (agent
->compatibility
== NICE_COMPATIBILITY_MSN
) {
639 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
640 STUN_COMPATIBILITY_RFC3489
,
641 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
642 STUN_AGENT_USAGE_FORCE_VALIDATER
);
643 } else if (agent
->compatibility
== NICE_COMPATIBILITY_WLM2009
) {
644 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
645 STUN_COMPATIBILITY_WLM2009
,
646 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
647 STUN_AGENT_USAGE_USE_FINGERPRINT
);
649 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
650 STUN_COMPATIBILITY_RFC5389
,
651 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
652 STUN_AGENT_USAGE_USE_FINGERPRINT
);
657 case PROP_STUN_SERVER
:
658 agent
->stun_server_ip
= g_value_dup_string (value
);
661 case PROP_STUN_SERVER_PORT
:
662 agent
->stun_server_port
= g_value_get_uint (value
);
665 case PROP_CONTROLLING_MODE
:
666 agent
->controlling_mode
= g_value_get_boolean (value
);
670 agent
->full_mode
= g_value_get_boolean (value
);
673 case PROP_STUN_PACING_TIMER
:
674 agent
->timer_ta
= g_value_get_uint (value
);
677 case PROP_MAX_CONNECTIVITY_CHECKS
:
678 agent
->max_conn_checks
= g_value_get_uint (value
);
682 agent
->proxy_ip
= g_value_dup_string (value
);
685 case PROP_PROXY_PORT
:
686 agent
->proxy_port
= g_value_get_uint (value
);
689 case PROP_PROXY_TYPE
:
690 agent
->proxy_type
= g_value_get_uint (value
);
693 case PROP_PROXY_USERNAME
:
694 agent
->proxy_username
= g_value_dup_string (value
);
697 case PROP_PROXY_PASSWORD
:
698 agent
->proxy_password
= g_value_dup_string (value
);
702 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
705 g_static_rec_mutex_unlock (&agent
->mutex
);
709 void agent_gathering_done (NiceAgent
*agent
)
712 GSList
*i
, *j
, *k
, *l
, *m
;
714 for (i
= agent
->streams
; i
; i
= i
->next
) {
715 Stream
*stream
= i
->data
;
716 for (j
= stream
->components
; j
; j
= j
->next
) {
717 Component
*component
= j
->data
;
719 for (k
= component
->local_candidates
; k
; k
= k
->next
) {
720 NiceCandidate
*local_candidate
= k
->data
;
722 gchar tmpbuf
[INET6_ADDRSTRLEN
];
723 nice_address_to_string (&local_candidate
->addr
, tmpbuf
);
724 nice_debug ("Agent %p: gathered local candidate : [%s]:%u"
725 " for s%d/c%d. U/P '%s'/'%s'", agent
,
726 tmpbuf
, nice_address_get_port (&local_candidate
->addr
),
727 local_candidate
->stream_id
, local_candidate
->component_id
,
728 local_candidate
->username
, local_candidate
->password
);
730 for (l
= component
->remote_candidates
; l
; l
= l
->next
) {
731 NiceCandidate
*remote_candidate
= l
->data
;
733 for (m
= stream
->conncheck_list
; m
; m
= m
->next
) {
734 CandidateCheckPair
*p
= m
->data
;
736 if (p
->local
== local_candidate
&& p
->remote
== remote_candidate
)
740 conn_check_add_for_candidate (agent
, stream
->id
, component
, remote_candidate
);
747 agent_signal_gathering_done (agent
);
750 void agent_signal_gathering_done (NiceAgent
*agent
)
754 for (i
= agent
->streams
; i
; i
= i
->next
) {
755 Stream
*stream
= i
->data
;
756 if (stream
->gathering
) {
757 stream
->gathering
= FALSE
;
758 g_signal_emit (agent
, signals
[SIGNAL_CANDIDATE_GATHERING_DONE
], 0, stream
->id
);
763 void agent_signal_initial_binding_request_received (NiceAgent
*agent
, Stream
*stream
)
765 if (stream
->initial_binding_request_received
!= TRUE
) {
766 stream
->initial_binding_request_received
= TRUE
;
767 g_signal_emit (agent
, signals
[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED
], 0, stream
->id
);
771 void agent_signal_new_selected_pair (NiceAgent
*agent
, guint stream_id
, guint component_id
, const gchar
*local_foundation
, const gchar
*remote_foundation
)
773 Component
*component
;
777 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
780 lf_copy
= g_strdup (local_foundation
);
781 rf_copy
= g_strdup (remote_foundation
);
783 if (component
->selected_pair
.local
->type
== NICE_CANDIDATE_TYPE_RELAYED
) {
784 nice_turn_socket_set_peer (component
->selected_pair
.local
->sockptr
,
785 &component
->selected_pair
.remote
->addr
);
788 g_signal_emit (agent
, signals
[SIGNAL_NEW_SELECTED_PAIR
], 0,
789 stream_id
, component_id
, lf_copy
, rf_copy
);
795 void agent_signal_new_candidate (NiceAgent
*agent
, NiceCandidate
*candidate
)
797 g_signal_emit (agent
, signals
[SIGNAL_NEW_CANDIDATE
], 0,
798 candidate
->stream_id
,
799 candidate
->component_id
,
800 candidate
->foundation
);
803 void agent_signal_new_remote_candidate (NiceAgent
*agent
, NiceCandidate
*candidate
)
805 g_signal_emit (agent
, signals
[SIGNAL_NEW_REMOTE_CANDIDATE
], 0,
806 candidate
->stream_id
,
807 candidate
->component_id
,
808 candidate
->foundation
);
811 void agent_signal_component_state_change (NiceAgent
*agent
, guint stream_id
, guint component_id
, NiceComponentState state
)
813 Component
*component
;
815 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
818 if (component
->state
!= state
&& state
< NICE_COMPONENT_STATE_LAST
) {
819 nice_debug ("Agent %p : stream %u component %u STATE-CHANGE %u -> %u.", agent
,
820 stream_id
, component_id
, component
->state
, state
);
822 component
->state
= state
;
824 g_signal_emit (agent
, signals
[SIGNAL_COMPONENT_STATE_CHANGED
], 0,
825 stream_id
, component_id
, state
);
830 agent_candidate_pair_priority (NiceAgent
*agent
, NiceCandidate
*local
, NiceCandidate
*remote
)
832 if (agent
->controlling_mode
)
833 return nice_candidate_pair_priority (local
->priority
, remote
->priority
);
835 return nice_candidate_pair_priority (remote
->priority
, local
->priority
);
839 priv_add_new_candidate_discovery_stun (NiceAgent
*agent
,
840 NiceSocket
*socket
, NiceAddress server
,
841 Stream
*stream
, guint component_id
)
843 CandidateDiscovery
*cdisco
;
844 GSList
*modified_list
;
846 /* note: no need to check for redundant candidates, as this is
847 * done later on in the process */
849 cdisco
= g_slice_new0 (CandidateDiscovery
);
851 modified_list
= g_slist_append (agent
->discovery_list
, cdisco
);
854 cdisco
->type
= NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE
;
855 cdisco
->nicesock
= socket
;
856 cdisco
->server
= server
;
857 cdisco
->stream
= stream
;
858 cdisco
->component
= stream_find_component_by_id (stream
, component_id
);
859 cdisco
->agent
= agent
;
860 stun_agent_init (&cdisco
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
861 STUN_COMPATIBILITY_RFC3489
, 0);
863 nice_debug ("Agent %p : Adding new srv-rflx candidate discovery %p\n", agent
, cdisco
);
864 agent
->discovery_list
= modified_list
;
865 ++agent
->discovery_unsched_items
;
875 priv_add_new_candidate_discovery_turn (NiceAgent
*agent
,
876 NiceSocket
*socket
, TurnServer
*turn
,
877 Stream
*stream
, guint component_id
)
879 CandidateDiscovery
*cdisco
;
880 GSList
*modified_list
;
881 GSList
*socket_modified_list
;
883 /* note: no need to check for redundant candidates, as this is
884 * done later on in the process */
886 cdisco
= g_slice_new0 (CandidateDiscovery
);
888 modified_list
= g_slist_append (agent
->discovery_list
, cdisco
);
891 Component
*component
= stream_find_component_by_id (stream
, component_id
);
893 cdisco
->type
= NICE_CANDIDATE_TYPE_RELAYED
;
895 if (turn
->type
== NICE_RELAY_TYPE_TURN_UDP
) {
896 if (agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
) {
897 NiceAddress addr
= socket
->addr
;
898 NiceSocket
*new_socket
;
899 nice_address_set_port (&addr
, 0);
901 new_socket
= nice_udp_bsd_socket_new (&addr
);
903 agent_attach_stream_component_socket (agent
, stream
,
904 component
, new_socket
);
905 socket_modified_list
= g_slist_append (component
->sockets
, new_socket
);
906 if (socket_modified_list
) {
907 /* success: store a pointer to the sockaddr */
908 component
->sockets
= socket_modified_list
;
911 nice_socket_free (new_socket
);
915 cdisco
->nicesock
= socket
;
917 NiceAddress proxy_server
;
920 if (agent
->proxy_type
!= NICE_PROXY_TYPE_NONE
&&
921 agent
->proxy_ip
!= NULL
&&
922 nice_address_set_from_string (&proxy_server
, agent
->proxy_ip
)) {
923 nice_address_set_port (&proxy_server
, agent
->proxy_port
);
924 socket
= nice_tcp_bsd_socket_new (agent
, component
->ctx
, &proxy_server
);
927 if (agent
->proxy_type
== NICE_PROXY_TYPE_SOCKS5
) {
928 socket
= nice_socks5_socket_new (socket
, &turn
->server
,
929 agent
->proxy_username
, agent
->proxy_password
);
930 } else if (agent
->proxy_type
== NICE_PROXY_TYPE_HTTP
){
931 socket
= nice_http_socket_new (socket
, &turn
->server
,
932 agent
->proxy_username
, agent
->proxy_password
);
934 /* TODO add HTTP support */
935 nice_socket_free (socket
);
941 if (socket
== NULL
) {
942 socket
= nice_tcp_bsd_socket_new (agent
, component
->ctx
, &turn
->server
);
944 if (turn
->type
== NICE_RELAY_TYPE_TURN_TLS
&&
945 agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
) {
946 socket
= nice_pseudossl_socket_new (agent
, socket
);
948 cdisco
->nicesock
= nice_tcp_turn_socket_new (agent
, socket
,
949 agent_to_turn_socket_compatibility (agent
));
951 if (!cdisco
->nicesock
) {
952 agent
->discovery_list
= g_slist_remove (modified_list
, cdisco
);
953 g_slice_free (CandidateDiscovery
, cdisco
);
957 agent_attach_stream_component_socket (agent
, stream
,
958 component
, cdisco
->nicesock
);
959 socket_modified_list
= g_slist_append (component
->sockets
, cdisco
->nicesock
);
960 if (socket_modified_list
) {
961 /* success: store a pointer to the sockaddr */
962 component
->sockets
= socket_modified_list
;
966 cdisco
->server
= turn
->server
;
968 cdisco
->stream
= stream
;
969 cdisco
->component
= stream_find_component_by_id (stream
, component_id
);
970 cdisco
->agent
= agent
;
972 if (agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
) {
973 stun_agent_init (&cdisco
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
974 STUN_COMPATIBILITY_RFC3489
,
975 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
976 STUN_AGENT_USAGE_IGNORE_CREDENTIALS
);
977 } else if (agent
->compatibility
== NICE_COMPATIBILITY_MSN
||
978 agent
->compatibility
== NICE_COMPATIBILITY_WLM2009
) {
979 stun_agent_init (&cdisco
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
980 STUN_COMPATIBILITY_RFC3489
,
981 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
);
983 stun_agent_init (&cdisco
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
984 STUN_COMPATIBILITY_RFC5389
,
985 STUN_AGENT_USAGE_ADD_SOFTWARE
|
986 STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS
);
989 nice_debug ("Agent %p : Adding new relay-rflx candidate discovery %p\n",
991 agent
->discovery_list
= modified_list
;
992 ++agent
->discovery_unsched_items
;
1001 NICEAPI_EXPORT guint
1002 nice_agent_add_stream (
1007 GSList
*modified_list
= NULL
;
1010 g_static_rec_mutex_lock (&agent
->mutex
);
1012 stream
= stream_new (n_components
);
1014 modified_list
= g_slist_append (agent
->streams
, stream
);
1015 if (modified_list
) {
1016 stream
->id
= agent
->next_stream_id
++;
1017 nice_debug ("Agent %p : allocating stream id %u (%p)", agent
, stream
->id
, stream
);
1019 stream_initialize_credentials (stream
, agent
->rng
);
1021 agent
->streams
= modified_list
;
1024 stream_free (stream
);
1029 g_static_rec_mutex_unlock (&agent
->mutex
);
1034 NICEAPI_EXPORT gboolean
1035 nice_agent_set_relay_info(NiceAgent
*agent
,
1036 guint stream_id
, guint component_id
,
1037 const gchar
*server_ip
, guint server_port
,
1038 const gchar
*username
, const gchar
*password
,
1042 Component
*component
= NULL
;
1044 g_return_val_if_fail (server_ip
, FALSE
);
1045 g_return_val_if_fail (server_port
, FALSE
);
1046 g_return_val_if_fail (username
, FALSE
);
1047 g_return_val_if_fail (password
, FALSE
);
1048 g_return_val_if_fail (type
<= NICE_PROXY_TYPE_LAST
, FALSE
);
1050 g_static_rec_mutex_lock (&agent
->mutex
);
1052 if (agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
)) {
1053 TurnServer
*turn
= g_slice_new0 (TurnServer
);
1054 nice_address_init (&turn
->server
);
1056 if (nice_address_set_from_string (&turn
->server
, server_ip
)) {
1057 nice_address_set_port (&turn
->server
, server_port
);
1059 g_slice_free (TurnServer
, turn
);
1060 g_static_rec_mutex_unlock (&agent
->mutex
);
1065 turn
->username
= g_strdup (username
);
1066 turn
->password
= g_strdup (password
);
1069 nice_debug ("Agent %p: added relay server [%s]:%d of type %d", agent
,
1070 server_ip
, server_port
, type
);
1072 component
->turn_servers
= g_list_append (component
->turn_servers
, turn
);
1075 g_static_rec_mutex_unlock (&agent
->mutex
);
1081 nice_agent_gather_candidates (
1089 g_static_rec_mutex_lock (&agent
->mutex
);
1091 stream
= agent_find_stream (agent
, stream_id
);
1092 if (stream
== NULL
) {
1096 nice_debug ("Agent %p : In %s mode, starting candidate gathering.", agent
,
1097 agent
->full_mode
? "ICE-FULL" : "ICE-LITE");
1099 /* if no local addresses added, generate them ourselves */
1100 if (agent
->local_addresses
== NULL
) {
1101 GList
*addresses
= nice_interfaces_get_local_ips (FALSE
);
1104 for (item
= addresses
; item
; item
= g_list_next (item
)) {
1105 NiceAddress
*addr
= nice_address_new ();
1107 if (nice_address_set_from_string (addr
, item
->data
)) {
1108 nice_agent_add_local_address (agent
, addr
);
1110 nice_address_free (addr
);
1113 g_list_foreach (addresses
, (GFunc
) g_free
, NULL
);
1114 g_list_free (addresses
);
1117 /* generate a local host candidate for each local address */
1118 for (i
= agent
->local_addresses
; i
; i
= i
->next
){
1119 NiceAddress
*addr
= i
->data
;
1120 NiceCandidate
*host_candidate
;
1122 for (n
= 0; n
< stream
->n_components
; n
++) {
1123 Component
*component
= stream_find_component_by_id (stream
, n
+ 1);
1124 host_candidate
= discovery_add_local_host_candidate (agent
, stream
->id
,
1127 if (!host_candidate
) {
1128 g_error ("No host candidate??");
1132 if (agent
->full_mode
&&
1133 agent
->stun_server_ip
) {
1134 NiceAddress stun_server
;
1135 if (nice_address_set_from_string (&stun_server
, agent
->stun_server_ip
)) {
1137 nice_address_set_port (&stun_server
, agent
->stun_server_port
);
1140 priv_add_new_candidate_discovery_stun (agent
,
1141 host_candidate
->sockptr
,
1147 /* note: memory allocation failure, return error */
1148 g_error ("Memory allocation failure?");
1153 if (agent
->full_mode
&& component
) {
1156 for (item
= component
->turn_servers
; item
; item
= item
->next
) {
1157 TurnServer
*turn
= item
->data
;
1160 priv_add_new_candidate_discovery_turn (agent
,
1161 host_candidate
->sockptr
,
1167 /* note: memory allocation failure, return error */
1168 g_error ("Memory allocation failure?");
1175 stream
->gathering
= TRUE
;
1178 /* note: no async discoveries pending, signal that we are ready */
1179 if (agent
->discovery_unsched_items
== 0) {
1180 nice_debug ("Agent %p: Candidate gathering FINISHED, no scheduled items.",
1182 agent_gathering_done (agent
);
1184 g_assert (agent
->discovery_list
);
1185 discovery_schedule (agent
);
1190 g_static_rec_mutex_unlock (&agent
->mutex
);
1193 static void priv_remove_keepalive_timer (NiceAgent
*agent
)
1195 if (agent
->keepalive_timer_source
!= NULL
) {
1196 g_source_destroy (agent
->keepalive_timer_source
);
1197 g_source_unref (agent
->keepalive_timer_source
);
1198 agent
->keepalive_timer_source
= NULL
;
1203 nice_agent_remove_stream (
1207 /* note that streams/candidates can be in use by other threads */
1212 g_static_rec_mutex_lock (&agent
->mutex
);
1213 stream
= agent_find_stream (agent
, stream_id
);
1219 /* note: remove items with matching stream_ids from both lists */
1220 conn_check_prune_stream (agent
, stream
);
1221 discovery_prune_stream (agent
, stream_id
);
1222 refresh_prune_stream (agent
, stream_id
);
1224 /* remove the stream itself */
1225 for (i
= stream
->components
; i
; i
= i
->next
) {
1226 priv_detach_stream_component (stream
, (Component
*) i
->data
);
1229 agent
->streams
= g_slist_remove (agent
->streams
, stream
);
1230 stream_free (stream
);
1232 if (!agent
->streams
)
1233 priv_remove_keepalive_timer (agent
);
1236 g_static_rec_mutex_unlock (&agent
->mutex
);
1239 NICEAPI_EXPORT gboolean
1240 nice_agent_add_local_address (NiceAgent
*agent
, NiceAddress
*addr
)
1243 GSList
*modified_list
;
1244 gboolean ret
= FALSE
;
1246 g_static_rec_mutex_lock (&agent
->mutex
);
1248 dup
= nice_address_dup (addr
);
1249 nice_address_set_port (dup
, 0);
1250 modified_list
= g_slist_append (agent
->local_addresses
, dup
);
1251 if (modified_list
) {
1252 agent
->local_addresses
= modified_list
;
1259 g_static_rec_mutex_unlock (&agent
->mutex
);
1263 static gboolean
priv_add_remote_candidate (
1267 NiceCandidateType type
,
1268 const NiceAddress
*addr
,
1269 const NiceAddress
*base_addr
,
1270 NiceCandidateTransport transport
,
1272 const gchar
*username
,
1273 const gchar
*password
,
1274 const gchar
*foundation
)
1276 Component
*component
;
1277 NiceCandidate
*candidate
;
1278 gboolean error_flag
= FALSE
;
1280 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
1283 /* step: check whether the candidate already exists */
1284 candidate
= component_find_remote_candidate(component
, addr
, transport
);
1286 nice_debug ("Agent %p : Update existing remote candidate %p.", agent
, candidate
);
1287 /* case 1: an existing candidate, update the attributes */
1288 candidate
->type
= type
;
1290 candidate
->base_addr
= *base_addr
;
1291 candidate
->priority
= priority
;
1293 strncpy(candidate
->foundation
, foundation
, NICE_CANDIDATE_MAX_FOUNDATION
);
1294 /* note: username and password must remain the same during
1295 * a session; see sect 9.1.2 in ICE ID-19 */
1296 if (conn_check_add_for_candidate (agent
, stream_id
, component
, candidate
) < 0)
1300 /* case 2: add a new candidate */
1302 candidate
= nice_candidate_new (type
);
1304 GSList
*modified_list
= g_slist_append (component
->remote_candidates
, candidate
);
1305 if (modified_list
) {
1306 component
->remote_candidates
= modified_list
;
1308 candidate
->stream_id
= stream_id
;
1309 candidate
->component_id
= component_id
;
1311 candidate
->type
= type
;
1313 candidate
->addr
= *addr
;
1315 gchar tmpbuf
[INET6_ADDRSTRLEN
];
1316 nice_address_to_string (addr
, tmpbuf
);
1317 nice_debug ("Agent %p : Adding remote candidate with addr [%s]:%u"
1318 " for s%d/c%d. U/P '%s'/'%s'", agent
, tmpbuf
,
1319 nice_address_get_port (addr
), stream_id
, component_id
,
1320 username
, password
);
1324 candidate
->base_addr
= *base_addr
;
1326 candidate
->transport
= transport
;
1327 candidate
->priority
= priority
;
1328 candidate
->username
= g_strdup (username
);
1329 candidate
->password
= g_strdup (password
);
1332 g_strlcpy (candidate
->foundation
, foundation
, NICE_CANDIDATE_MAX_FOUNDATION
);
1334 if (conn_check_add_for_candidate (agent
, stream_id
, component
, candidate
) < 0)
1337 else /* memory alloc error: list insert */
1340 else /* memory alloc error: candidate creation */
1346 nice_candidate_free (candidate
);
1353 NICEAPI_EXPORT gboolean
1354 nice_agent_set_remote_credentials (
1357 const gchar
*ufrag
, const gchar
*pwd
)
1360 gboolean ret
= FALSE
;
1362 g_static_rec_mutex_lock (&agent
->mutex
);
1364 stream
= agent_find_stream (agent
, stream_id
);
1365 /* note: oddly enough, ufrag and pwd can be empty strings */
1366 if (stream
&& ufrag
&& pwd
) {
1368 g_strlcpy (stream
->remote_ufrag
, ufrag
, NICE_STREAM_MAX_UFRAG
);
1369 g_strlcpy (stream
->remote_password
, pwd
, NICE_STREAM_MAX_PWD
);
1376 g_static_rec_mutex_unlock (&agent
->mutex
);
1381 NICEAPI_EXPORT gboolean
1382 nice_agent_get_local_credentials (
1385 gchar
**ufrag
, gchar
**pwd
)
1388 gboolean ret
= TRUE
;
1390 g_static_rec_mutex_lock (&agent
->mutex
);
1392 stream
= agent_find_stream (agent
, stream_id
);
1393 if (stream
== NULL
) {
1397 if (!ufrag
|| !pwd
) {
1401 *ufrag
= g_strdup (stream
->local_ufrag
);
1402 *pwd
= g_strdup (stream
->local_password
);
1407 g_static_rec_mutex_unlock (&agent
->mutex
);
1412 nice_agent_set_remote_candidates (NiceAgent
*agent
, guint stream_id
, guint component_id
, const GSList
*candidates
)
1418 nice_debug ("Agent %p: set_remote_candidates %d %d", agent
, stream_id
, component_id
);
1420 g_static_rec_mutex_lock (&agent
->mutex
);
1422 stream
= agent_find_stream (agent
, stream_id
);
1423 if (stream
== NULL
) {
1428 if (agent
->discovery_unsched_items
> 0 || stream
->gathering
) {
1429 nice_debug ("Agent %p: Remote candidates refused for stream %d because "
1430 "we are still gathering our own candidates", agent
, stream_id
);
1435 for (i
= candidates
; i
&& added
>= 0; i
= i
->next
) {
1436 NiceCandidate
*d
= (NiceCandidate
*) i
->data
;
1438 priv_add_remote_candidate (agent
,
1455 conn_check_remote_candidates_set(agent
);
1458 gboolean res
= conn_check_schedule_next (agent
);
1460 nice_debug ("Agent %p : Warning: unable to schedule any conn checks!", agent
);
1464 g_static_rec_mutex_unlock (&agent
->mutex
);
1473 Component
*component
,
1482 len
= nice_socket_recv (socket
, &from
, buf_len
, buf
);
1489 gchar tmpbuf
[INET6_ADDRSTRLEN
];
1490 nice_address_to_string (&from
, tmpbuf
);
1491 nice_debug ("Agent %p : Packet received on local socket %u from [%s]:%u (%u octets).", agent
,
1492 socket
->fileno
, tmpbuf
, nice_address_get_port (&from
), len
);
1497 if ((guint
)len
> buf_len
)
1499 /* buffer is not big enough to accept this packet */
1500 /* XXX: test this case */
1504 for (item
= component
->turn_servers
; item
; item
= g_list_next (item
)) {
1505 TurnServer
*turn
= item
->data
;
1506 if (nice_address_equal (&from
, &turn
->server
)) {
1509 nice_debug ("Agent %p : Packet received from TURN server candidate.",
1512 for (i
= component
->local_candidates
; i
; i
= i
->next
) {
1513 NiceCandidate
*cand
= i
->data
;
1514 if (cand
->type
== NICE_CANDIDATE_TYPE_RELAYED
&&
1515 cand
->stream_id
== stream
->id
&&
1516 cand
->component_id
== component
->id
) {
1517 len
= nice_turn_socket_parse_recv (cand
->sockptr
, &socket
,
1518 &from
, len
, buf
, &from
, buf
, len
);
1525 if (stun_message_validate_buffer_length ((uint8_t *) buf
, (size_t) len
) != len
)
1526 /* If the retval is no 0, its not a valid stun packet, probably data */
1530 if (conn_check_handle_inbound_stun (agent
, stream
, component
, socket
,
1532 /* handled STUN message*/
1535 /* unhandled STUN, pass to client */
1549 Component
*component
;
1552 g_static_rec_mutex_lock (&agent
->mutex
);
1554 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1558 if (component
->selected_pair
.local
!= NULL
)
1564 gchar tmpbuf
[INET6_ADDRSTRLEN
];
1565 nice_address_to_string (&component
->selected_pair
.remote
->addr
, tmpbuf
);
1567 nice_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", agent
, stream_id
, component_id
,
1569 nice_address_get_port (&component
->selected_pair
.remote
->addr
));
1572 sock
= component
->selected_pair
.local
->sockptr
;
1573 addr
= &component
->selected_pair
.remote
->addr
;
1574 if (nice_socket_send (sock
, addr
, len
, buf
)) {
1581 g_static_rec_mutex_unlock (&agent
->mutex
);
1586 NICEAPI_EXPORT GSList
*
1587 nice_agent_get_local_candidates (
1592 Component
*component
;
1593 GSList
* ret
= NULL
;
1594 GSList
* item
= NULL
;
1596 g_static_rec_mutex_lock (&agent
->mutex
);
1597 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
1602 for (item
= component
->local_candidates
; item
; item
= item
->next
)
1603 ret
= g_slist_append (ret
, nice_candidate_copy (item
->data
));
1606 g_static_rec_mutex_unlock (&agent
->mutex
);
1611 NICEAPI_EXPORT GSList
*
1612 nice_agent_get_remote_candidates (
1617 Component
*component
;
1618 GSList
*ret
= NULL
, *item
= NULL
;
1620 g_static_rec_mutex_lock (&agent
->mutex
);
1621 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
1626 for (item
= component
->remote_candidates
; item
; item
= item
->next
)
1627 ret
= g_slist_append (ret
, nice_candidate_copy (item
->data
));
1630 g_static_rec_mutex_unlock (&agent
->mutex
);
1636 nice_agent_restart (
1640 gboolean res
= TRUE
;
1642 g_static_rec_mutex_lock (&agent
->mutex
);
1644 /* step: clean up all connectivity checks */
1645 conn_check_free (agent
);
1647 /* step: regenerate tie-breaker value */
1648 priv_generate_tie_breaker (agent
);
1650 for (i
= agent
->streams
; i
&& res
; i
= i
->next
) {
1651 Stream
*stream
= i
->data
;
1653 /* step: reset local credentials for the stream and
1654 * clean up the list of remote candidates */
1655 res
= stream_restart (stream
, agent
->rng
);
1658 g_static_rec_mutex_unlock (&agent
->mutex
);
1663 nice_agent_dispose (GObject
*object
)
1666 NiceAgent
*agent
= NICE_AGENT (object
);
1668 /* step: free resources for the binding discovery timers */
1669 discovery_free (agent
);
1670 g_assert (agent
->discovery_list
== NULL
);
1671 refresh_free (agent
);
1672 g_assert (agent
->refresh_list
== NULL
);
1674 /* step: free resources for the connectivity check timers */
1675 conn_check_free (agent
);
1677 priv_remove_keepalive_timer (agent
);
1679 for (i
= agent
->local_addresses
; i
; i
= i
->next
)
1681 NiceAddress
*a
= i
->data
;
1683 nice_address_free (a
);
1686 g_slist_free (agent
->local_addresses
);
1687 agent
->local_addresses
= NULL
;
1689 for (i
= agent
->streams
; i
; i
= i
->next
)
1691 Stream
*s
= i
->data
;
1696 g_slist_free (agent
->streams
);
1697 agent
->streams
= NULL
;
1699 g_free (agent
->stun_server_ip
);
1700 agent
->stun_server_ip
= NULL
;
1702 nice_rng_free (agent
->rng
);
1705 if (G_OBJECT_CLASS (nice_agent_parent_class
)->dispose
)
1706 G_OBJECT_CLASS (nice_agent_parent_class
)->dispose (object
);
1708 g_static_rec_mutex_free (&agent
->mutex
);
1712 typedef struct _IOCtx IOCtx
;
1716 GIOChannel
*channel
;
1720 Component
*component
;
1729 Component
*component
,
1731 GIOChannel
*channel
,
1736 ctx
= g_slice_new0 (IOCtx
);
1739 ctx
->stream
= stream
;
1740 ctx
->component
= component
;
1741 ctx
->socket
= socket
;
1742 ctx
->channel
= channel
;
1743 ctx
->source
= source
;
1750 io_ctx_free (IOCtx
*ctx
)
1752 g_io_channel_unref (ctx
->channel
);
1753 g_slice_free (IOCtx
, ctx
);
1757 nice_agent_g_source_cb (
1760 GIOCondition condition
,
1763 /* return value is whether to keep the source */
1766 NiceAgent
*agent
= ctx
->agent
;
1767 Stream
*stream
= ctx
->stream
;
1768 Component
*component
= ctx
->component
;
1769 gchar buf
[MAX_BUFFER_SIZE
];
1772 g_static_rec_mutex_lock (&agent
->mutex
);
1774 /* note: dear compiler, these are for you: */
1777 len
= _nice_agent_recv (agent
, stream
, component
, ctx
->socket
,
1778 MAX_BUFFER_SIZE
, buf
);
1780 if (len
> 0 && component
->g_source_io_cb
) {
1781 component
->g_source_io_cb (agent
, stream
->id
, component
->id
,
1782 len
, buf
, component
->data
);
1783 } else if (len
< 0) {
1784 GSource
*source
= ctx
->source
;
1785 component
->gsources
= g_slist_remove (component
->gsources
, source
);
1786 g_source_destroy (source
);
1787 g_source_unref (source
);
1788 /* We don't close the socket because it would be way too complicated to
1789 * take care of every path where the socket might still be used.. */
1790 nice_debug ("Agent %p: unable to recv from socket %p. Detaching", agent
,
1794 g_static_rec_mutex_unlock (&agent
->mutex
);
1799 * Attaches one socket handle to the main loop event context
1803 agent_attach_stream_component_socket (NiceAgent
*agent
,
1805 Component
*component
,
1812 if (!component
->ctx
)
1815 io
= g_io_channel_unix_new (socket
->fileno
);
1816 /* note: without G_IO_ERR the glib mainloop goes into
1817 * busyloop if errors are encountered */
1818 source
= g_io_create_watch (io
, G_IO_IN
| G_IO_ERR
);
1819 ctx
= io_ctx_new (agent
, stream
, component
, socket
, io
, source
);
1820 g_source_set_callback (source
, (GSourceFunc
) nice_agent_g_source_cb
,
1821 ctx
, (GDestroyNotify
) io_ctx_free
);
1822 nice_debug ("Agent %p : Attach source %p (stream %u).", agent
, source
, stream
->id
);
1823 g_source_attach (source
, component
->ctx
);
1824 component
->gsources
= g_slist_append (component
->gsources
, source
);
1829 * Attaches socket handles of 'stream' to the main eventloop
1834 priv_attach_stream_component (NiceAgent
*agent
,
1836 Component
*component
)
1840 for (i
= component
->sockets
; i
; i
= i
->next
)
1841 agent_attach_stream_component_socket (agent
, stream
, component
, i
->data
);
1847 * Detaches socket handles of 'stream' from the main eventloop
1851 static void priv_detach_stream_component (Stream
*stream
, Component
*component
)
1855 for (i
= component
->gsources
; i
; i
= i
->next
) {
1856 GSource
*source
= i
->data
;
1857 nice_debug ("Detach source %p (stream %u).", source
, stream
->id
);
1858 g_source_destroy (source
);
1859 g_source_unref (source
);
1862 g_slist_free (component
->gsources
);
1863 component
->gsources
= NULL
;
1866 NICEAPI_EXPORT gboolean
1867 nice_agent_attach_recv (
1872 NiceAgentRecvFunc func
,
1875 Component
*component
= NULL
;
1876 Stream
*stream
= NULL
;
1877 gboolean ret
= FALSE
;
1879 g_static_rec_mutex_lock (&agent
->mutex
);
1881 /* attach candidates */
1883 /* step: check that params specify an existing pair */
1884 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1885 g_warning ("Could not find component %u in stream %u", component_id
,
1890 if (component
->g_source_io_cb
&& func
== NULL
)
1891 priv_detach_stream_component (stream
, component
);
1896 component
->g_source_io_cb
= func
;
1897 component
->data
= data
;
1898 component
->ctx
= ctx
;
1899 priv_attach_stream_component (agent
, stream
, component
);
1901 component
->g_source_io_cb
= NULL
;
1902 component
->data
= NULL
;
1903 component
->ctx
= NULL
;
1908 g_static_rec_mutex_unlock (&agent
->mutex
);
1912 NICEAPI_EXPORT gboolean
1913 nice_agent_set_selected_pair (
1917 const gchar
*lfoundation
,
1918 const gchar
*rfoundation
)
1920 Component
*component
;
1923 gboolean ret
= FALSE
;
1925 g_static_rec_mutex_lock (&agent
->mutex
);
1927 /* step: check that params specify an existing pair */
1928 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1932 if (!component_find_pair (component
, agent
, lfoundation
, rfoundation
, &pair
)){
1936 /* step: stop connectivity checks (note: for the whole stream) */
1937 conn_check_prune_stream (agent
, stream
);
1939 /* step: change component state */
1940 agent_signal_component_state_change (agent
, stream_id
, component_id
, NICE_COMPONENT_STATE_READY
);
1942 /* step: set the selected pair */
1943 component_update_selected_pair (component
, &pair
);
1944 agent_signal_new_selected_pair (agent
, stream_id
, component_id
, lfoundation
, rfoundation
);
1949 g_static_rec_mutex_unlock (&agent
->mutex
);
1954 GSource
* agent_timeout_add_with_context (NiceAgent
*agent
, guint interval
,
1955 GSourceFunc function
, gpointer data
)
1960 g_return_val_if_fail (function
!= NULL
, 0);
1962 source
= g_timeout_source_new (interval
);
1964 g_source_set_callback (source
, function
, data
, NULL
);
1965 id
= g_source_attach (source
, agent
->main_context
);
1971 NICEAPI_EXPORT gboolean
1972 nice_agent_set_selected_remote_candidate (
1976 NiceCandidate
*candidate
)
1978 Component
*component
;
1980 NiceCandidate
*lcandidate
= NULL
;
1981 gboolean ret
= FALSE
;
1983 g_static_rec_mutex_lock (&agent
->mutex
);
1985 /* step: check if the component exists*/
1986 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
1990 /* step: stop connectivity checks (note: for the whole stream) */
1991 conn_check_prune_stream (agent
, stream
);
1994 /* step: set the selected pair */
1995 lcandidate
= component_set_selected_remote_candidate (agent
, component
,
2000 /* step: change component state */
2001 agent_signal_component_state_change (agent
, stream_id
, component_id
, NICE_COMPONENT_STATE_READY
);
2003 agent_signal_new_selected_pair (agent
, stream_id
, component_id
,
2004 lcandidate
->foundation
,
2005 candidate
->foundation
);
2010 g_static_rec_mutex_unlock (&agent
->mutex
);