2 * This file is part of the Nice GLib ICE library.
4 * (C) 2006-2010 Collabora Ltd.
5 * Contact: Youness Alaoui
6 * (C) 2006-2010 Nokia Corporation. All rights reserved.
7 * Contact: Kai Vehmanen
9 * The contents of this file are subject to the Mozilla Public License Version
10 * 1.1 (the "License"); you may not use this file except in compliance with
11 * the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS" basis,
15 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 * for the specific language governing rights and limitations under the
19 * The Original Code is the Nice GLib ICE library.
21 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
22 * Corporation. All Rights Reserved.
25 * Dafydd Harries, Collabora Ltd.
26 * Youness Alaoui, Collabora Ltd.
29 * Alternatively, the contents of this file may be used under the terms of the
30 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
31 * case the provisions of LGPL are applicable instead of those above. If you
32 * wish to allow use of your version of this file only under the terms of the
33 * LGPL and not to allow others to use your version of this file under the
34 * MPL, indicate your decision by deleting the provisions above and replace
35 * them with the notice and other provisions required by the LGPL. If you do
36 * not delete the provisions above, a recipient may use your version of this
37 * file under either the MPL or the LGPL.
44 #define NICEAPI_EXPORT
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
63 #include "stun/usages/turn.h"
64 #include "candidate.h"
65 #include "component.h"
66 #include "conncheck.h"
67 #include "discovery.h"
69 #include "agent-priv.h"
70 #include "agent-signals-marshal.h"
73 #include "interfaces.h"
75 #include "pseudotcp.h"
77 /* This is the max size of a UDP packet
78 * will it work tcp relaying??
80 #define MAX_BUFFER_SIZE 65536
81 #define DEFAULT_STUN_PORT 3478
82 #define DEFAULT_UPNP_TIMEOUT 200
84 #define MAX_TCP_MTU 1400 /* Use 1400 because of VPNs and we assume IEE 802.3 */
86 G_DEFINE_TYPE (NiceAgent
, nice_agent
, G_TYPE_OBJECT
);
90 PROP_COMPATIBILITY
= 1,
93 PROP_STUN_SERVER_PORT
,
94 PROP_CONTROLLING_MODE
,
96 PROP_STUN_PACING_TIMER
,
97 PROP_MAX_CONNECTIVITY_CHECKS
,
111 SIGNAL_COMPONENT_STATE_CHANGED
,
112 SIGNAL_CANDIDATE_GATHERING_DONE
,
113 SIGNAL_NEW_SELECTED_PAIR
,
114 SIGNAL_NEW_CANDIDATE
,
115 SIGNAL_NEW_REMOTE_CANDIDATE
,
116 SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED
,
117 SIGNAL_RELIABLE_TRANSPORT_WRITABLE
,
121 static guint signals
[N_SIGNALS
];
123 static GStaticRecMutex agent_mutex
= G_STATIC_REC_MUTEX_INIT
; /* Mutex used for thread-safe lib */
125 static gboolean
priv_attach_stream_component (NiceAgent
*agent
,
127 Component
*component
);
128 static void priv_detach_stream_component (Stream
*stream
, Component
*component
);
130 static void priv_free_upnp (NiceAgent
*agent
);
133 void agent_lock (void)
135 g_static_rec_mutex_lock (&agent_mutex
);
138 void agent_unlock (void)
140 g_static_rec_mutex_unlock (&agent_mutex
);
145 StunUsageIceCompatibility
146 agent_to_ice_compatibility (NiceAgent
*agent
)
148 return agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
?
149 STUN_USAGE_ICE_COMPATIBILITY_GOOGLE
:
150 agent
->compatibility
== NICE_COMPATIBILITY_MSN
?
151 STUN_USAGE_ICE_COMPATIBILITY_MSN
:
152 STUN_USAGE_ICE_COMPATIBILITY_RFC5245
;
156 StunUsageTurnCompatibility
157 agent_to_turn_compatibility (NiceAgent
*agent
)
159 return agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
?
160 STUN_USAGE_TURN_COMPATIBILITY_GOOGLE
:
161 agent
->compatibility
== NICE_COMPATIBILITY_MSN
?
162 STUN_USAGE_TURN_COMPATIBILITY_MSN
:
163 agent
->compatibility
== NICE_COMPATIBILITY_WLM2009
?
164 STUN_USAGE_TURN_COMPATIBILITY_MSN
: STUN_USAGE_TURN_COMPATIBILITY_DRAFT9
;
167 NiceTurnSocketCompatibility
168 agent_to_turn_socket_compatibility (NiceAgent
*agent
)
170 return agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
?
171 NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE
:
172 agent
->compatibility
== NICE_COMPATIBILITY_MSN
?
173 NICE_TURN_SOCKET_COMPATIBILITY_MSN
:
174 agent
->compatibility
== NICE_COMPATIBILITY_WLM2009
?
175 NICE_TURN_SOCKET_COMPATIBILITY_MSN
:
176 NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9
;
179 Stream
*agent_find_stream (NiceAgent
*agent
, guint stream_id
)
183 for (i
= agent
->streams
; i
; i
= i
->next
)
187 if (s
->id
== stream_id
)
196 agent_find_component (
201 Component
**component
)
206 s
= agent_find_stream (agent
, stream_id
);
211 c
= stream_find_component_by_id (s
, component_id
);
227 nice_agent_dispose (GObject
*object
);
230 nice_agent_get_property (
237 nice_agent_set_property (
245 nice_agent_class_init (NiceAgentClass
*klass
)
247 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
249 gobject_class
->get_property
= nice_agent_get_property
;
250 gobject_class
->set_property
= nice_agent_set_property
;
251 gobject_class
->dispose
= nice_agent_dispose
;
253 /* install properties */
255 * NiceAgent:main-context:
257 * A GLib main context is needed for all timeouts used by libnice.
258 * This is a property being set by the nice_agent_new() call.
260 g_object_class_install_property (gobject_class
, PROP_MAIN_CONTEXT
,
261 g_param_spec_pointer (
263 "The GMainContext to use for timeouts",
264 "The GMainContext to use for timeouts",
265 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
268 * NiceAgent:compatibility:
270 * The Nice agent can work in various compatibility modes depending on
271 * what the application/peer needs.
272 * <para> See also: #NiceCompatibility</para>
274 g_object_class_install_property (gobject_class
, PROP_COMPATIBILITY
,
277 "ICE specification compatibility",
278 "The compatibility mode for the agent",
279 NICE_COMPATIBILITY_RFC5245
, NICE_COMPATIBILITY_LAST
,
280 NICE_COMPATIBILITY_RFC5245
,
281 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
283 g_object_class_install_property (gobject_class
, PROP_STUN_SERVER
,
284 g_param_spec_string (
287 "The STUN server used to obtain server-reflexive candidates",
291 g_object_class_install_property (gobject_class
, PROP_STUN_SERVER_PORT
,
295 "The STUN server used to obtain server-reflexive candidates",
297 1, /* not a construct property, ignored */
300 g_object_class_install_property (gobject_class
, PROP_CONTROLLING_MODE
,
301 g_param_spec_boolean (
303 "ICE controlling mode",
304 "Whether the agent is in controlling mode",
305 FALSE
, /* not a construct property, ignored */
308 g_object_class_install_property (gobject_class
, PROP_FULL_MODE
,
309 g_param_spec_boolean (
312 "Whether agent runs in ICE full mode",
313 TRUE
, /* use full mode by default */
314 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
316 g_object_class_install_property (gobject_class
, PROP_STUN_PACING_TIMER
,
320 "Timer 'Ta' (msecs) used in the IETF ICE specification for pacing "
321 "candidate gathering and sending of connectivity checks",
323 NICE_AGENT_TIMER_TA_DEFAULT
,
324 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
326 /* note: according to spec recommendation in sect 5.7.3 (ID-19) */
327 g_object_class_install_property (gobject_class
, PROP_MAX_CONNECTIVITY_CHECKS
,
329 "max-connectivity-checks",
330 "Maximum number of connectivity checks",
331 "Upper limit for the total number of connectivity checks performed",
333 0, /* default set in init */
337 * NiceAgent:proxy-ip:
339 * The proxy server IP used to bypass a proxy firewall
343 g_object_class_install_property (gobject_class
, PROP_PROXY_IP
,
344 g_param_spec_string (
347 "The proxy server IP used to bypass a proxy firewall",
352 * NiceAgent:proxy-port:
354 * The proxy server port used to bypass a proxy firewall
358 g_object_class_install_property (gobject_class
, PROP_PROXY_PORT
,
362 "The Proxy server port used to bypass a proxy firewall",
368 * NiceAgent:proxy-type:
370 * The type of proxy set in the proxy-ip property
374 g_object_class_install_property (gobject_class
, PROP_PROXY_TYPE
,
377 "Type of proxy to use",
378 "The type of proxy set in the proxy-ip property",
379 NICE_PROXY_TYPE_NONE
, NICE_PROXY_TYPE_LAST
,
380 NICE_PROXY_TYPE_NONE
,
384 * NiceAgent:proxy-username:
386 * The username used to authenticate with the proxy
390 g_object_class_install_property (gobject_class
, PROP_PROXY_USERNAME
,
391 g_param_spec_string (
393 "Proxy server username",
394 "The username used to authenticate with the proxy",
399 * NiceAgent:proxy-password:
401 * The password used to authenticate with the proxy
405 g_object_class_install_property (gobject_class
, PROP_PROXY_PASSWORD
,
406 g_param_spec_string (
408 "Proxy server password",
409 "The password used to authenticate with the proxy",
416 * Whether the agent should use UPnP to open a port in the router and
417 * get the external IP
421 g_object_class_install_property (gobject_class
, PROP_UPNP
,
422 g_param_spec_boolean (
426 "Whether the agent should use UPnP to open a port in the router and "
427 "get the external IP",
429 "Use UPnP (disabled in build)",
430 "Does nothing because libnice was not built with UPnP support",
432 TRUE
, /* enable UPnP by default */
433 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
));
436 * NiceAgent:upnp-timeout:
438 * The maximum amount of time to wait for UPnP discovery to finish before
439 * signaling the #NiceAgent::candidate-gathering-done signal
443 g_object_class_install_property (gobject_class
, PROP_UPNP_TIMEOUT
,
447 "Timeout for UPnP discovery",
448 "The maximum amount of time to wait for UPnP discovery to finish before "
449 "signaling the candidate-gathering-done signal",
451 "Timeout for UPnP discovery (disabled in build)",
452 "Does nothing because libnice was not built with UPnP support",
455 DEFAULT_UPNP_TIMEOUT
,
456 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
));
459 * NiceAgent:reliable:
461 * Whether the agent should use PseudoTcp to ensure a reliable transport
466 g_object_class_install_property (gobject_class
, PROP_RELIABLE
,
467 g_param_spec_boolean (
470 "Whether the agent should use PseudoTcp to ensure a reliable transport"
473 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
475 /* install signals */
478 * NiceAgent::component-state-changed
479 * @agent: The #NiceAgent object
480 * @stream_id: The ID of the stream
481 * @component_id: The ID of the component
482 * @state: The #NiceComponentState of the component
484 * This signal is fired whenever a component's state changes
486 signals
[SIGNAL_COMPONENT_STATE_CHANGED
] =
488 "component-state-changed",
489 G_OBJECT_CLASS_TYPE (klass
),
494 agent_marshal_VOID__UINT_UINT_UINT
,
497 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_UINT
,
501 * NiceAgent::candidate-gathering-done:
502 * @agent: The #NiceAgent object
503 * @stream_id: The ID of the stream
505 * This signal is fired whenever a stream has finished gathering its
506 * candidates after a call to nice_agent_gather_candidates()
508 signals
[SIGNAL_CANDIDATE_GATHERING_DONE
] =
510 "candidate-gathering-done",
511 G_OBJECT_CLASS_TYPE (klass
),
516 agent_marshal_VOID__UINT
,
519 G_TYPE_UINT
, G_TYPE_INVALID
);
522 * NiceAgent::new-selected-pair
523 * @agent: The #NiceAgent object
524 * @stream_id: The ID of the stream
525 * @component_id: The ID of the component
526 * @lfoundation: The local foundation of the selected candidate pair
527 * @rfoundation: The remote foundation of the selected candidate pair
529 * This signal is fired once a candidate pair is selected for data transfer for
530 * a stream's component
532 signals
[SIGNAL_NEW_SELECTED_PAIR
] =
535 G_OBJECT_CLASS_TYPE (klass
),
540 agent_marshal_VOID__UINT_UINT_STRING_STRING
,
543 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_STRING
, G_TYPE_STRING
,
547 * NiceAgent::new-candidate
548 * @agent: The #NiceAgent object
549 * @stream_id: The ID of the stream
550 * @component_id: The ID of the component
551 * @foundation: The foundation of the new candidate
553 * This signal is fired when the agent discovers a new candidate
554 * <para> See also: #NiceAgent::candidate-gathering-done </para>
556 signals
[SIGNAL_NEW_CANDIDATE
] =
559 G_OBJECT_CLASS_TYPE (klass
),
564 agent_marshal_VOID__UINT_UINT_STRING
,
567 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_STRING
,
571 * NiceAgent::new-remote-candidate
572 * @agent: The #NiceAgent object
573 * @stream_id: The ID of the stream
574 * @component_id: The ID of the component
575 * @foundation: The foundation of the new candidate
577 * This signal is fired when the agent discovers a new remote candidate.
578 * This can happen with peer reflexive candidates.
580 signals
[SIGNAL_NEW_REMOTE_CANDIDATE
] =
582 "new-remote-candidate",
583 G_OBJECT_CLASS_TYPE (klass
),
588 agent_marshal_VOID__UINT_UINT_STRING
,
591 G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_STRING
,
595 * NiceAgent::initial-binding-request-received
596 * @agent: The #NiceAgent object
597 * @stream_id: The ID of the stream
599 * This signal is fired when we received our first binding request from
602 signals
[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED
] =
604 "initial-binding-request-received",
605 G_OBJECT_CLASS_TYPE (klass
),
610 agent_marshal_VOID__UINT
,
617 * NiceAgent::reliable-transport-writable
618 * @agent: The #NiceAgent object
619 * @stream_id: The ID of the stream
620 * @component_id: The ID of the component
622 * This signal is fired on the reliable #NiceAgent when the underlying reliable
623 * transport becomes writable.
624 * This signal is only emitted when the nice_agent_send() function returns less
625 * bytes than requested to send (or -1) and once when the connection
630 signals
[SIGNAL_RELIABLE_TRANSPORT_WRITABLE
] =
632 "reliable-transport-writable",
633 G_OBJECT_CLASS_TYPE (klass
),
638 agent_marshal_VOID__UINT_UINT
,
641 G_TYPE_UINT
, G_TYPE_UINT
,
645 /* Init debug options depending on env variables */
649 static void priv_generate_tie_breaker (NiceAgent
*agent
)
651 nice_rng_generate_bytes (agent
->rng
, 8, (gchar
*)&agent
->tie_breaker
);
655 nice_agent_init (NiceAgent
*agent
)
657 agent
->next_candidate_id
= 1;
658 agent
->next_stream_id
= 1;
660 /* set defaults; not construct params, so set here */
661 agent
->stun_server_port
= DEFAULT_STUN_PORT
;
662 agent
->controlling_mode
= TRUE
;
663 agent
->max_conn_checks
= NICE_AGENT_MAX_CONNECTIVITY_CHECKS_DEFAULT
;
665 agent
->discovery_list
= NULL
;
666 agent
->discovery_unsched_items
= 0;
667 agent
->discovery_timer_source
= NULL
;
668 agent
->conncheck_timer_source
= NULL
;
669 agent
->keepalive_timer_source
= NULL
;
670 agent
->refresh_list
= NULL
;
671 agent
->media_after_tick
= FALSE
;
672 agent
->software_attribute
= NULL
;
674 agent
->compatibility
= NICE_COMPATIBILITY_RFC5245
;
675 agent
->reliable
= FALSE
;
677 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
678 STUN_COMPATIBILITY_RFC5389
,
679 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
680 STUN_AGENT_USAGE_USE_FINGERPRINT
);
682 agent
->rng
= nice_rng_new ();
683 priv_generate_tie_breaker (agent
);
687 NICEAPI_EXPORT NiceAgent
*
688 nice_agent_new (GMainContext
*ctx
, NiceCompatibility compat
)
690 NiceAgent
*agent
= g_object_new (NICE_TYPE_AGENT
,
691 "compatibility", compat
,
700 NICEAPI_EXPORT NiceAgent
*
701 nice_agent_new_reliable (GMainContext
*ctx
, NiceCompatibility compat
)
703 NiceAgent
*agent
= g_object_new (NICE_TYPE_AGENT
,
704 "compatibility", compat
,
714 nice_agent_get_property (
720 NiceAgent
*agent
= NICE_AGENT (object
);
726 case PROP_MAIN_CONTEXT
:
727 g_value_set_pointer (value
, agent
->main_context
);
730 case PROP_COMPATIBILITY
:
731 g_value_set_uint (value
, agent
->compatibility
);
734 case PROP_STUN_SERVER
:
735 g_value_set_string (value
, agent
->stun_server_ip
);
738 case PROP_STUN_SERVER_PORT
:
739 g_value_set_uint (value
, agent
->stun_server_port
);
742 case PROP_CONTROLLING_MODE
:
743 g_value_set_boolean (value
, agent
->controlling_mode
);
747 g_value_set_boolean (value
, agent
->full_mode
);
750 case PROP_STUN_PACING_TIMER
:
751 g_value_set_uint (value
, agent
->timer_ta
);
754 case PROP_MAX_CONNECTIVITY_CHECKS
:
755 g_value_set_uint (value
, agent
->max_conn_checks
);
756 /* XXX: should we prune the list of already existing checks? */
760 g_value_set_string (value
, agent
->proxy_ip
);
763 case PROP_PROXY_PORT
:
764 g_value_set_uint (value
, agent
->proxy_port
);
767 case PROP_PROXY_TYPE
:
768 g_value_set_uint (value
, agent
->proxy_type
);
771 case PROP_PROXY_USERNAME
:
772 g_value_set_string (value
, agent
->proxy_username
);
775 case PROP_PROXY_PASSWORD
:
776 g_value_set_string (value
, agent
->proxy_password
);
781 g_value_set_boolean (value
, agent
->upnp_enabled
);
783 g_value_set_boolean (value
, FALSE
);
787 case PROP_UPNP_TIMEOUT
:
789 g_value_set_uint (value
, agent
->upnp_timeout
);
791 g_value_set_uint (value
, DEFAULT_UPNP_TIMEOUT
);
796 g_value_set_boolean (value
, agent
->reliable
);
800 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
808 nice_agent_set_property (
814 NiceAgent
*agent
= NICE_AGENT (object
);
820 case PROP_MAIN_CONTEXT
:
821 agent
->main_context
= g_value_get_pointer (value
);
822 if (agent
->main_context
!= NULL
)
823 g_main_context_ref (agent
->main_context
);
826 case PROP_COMPATIBILITY
:
827 agent
->compatibility
= g_value_get_uint (value
);
828 if (agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
) {
829 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
830 STUN_COMPATIBILITY_RFC3489
,
831 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
832 STUN_AGENT_USAGE_IGNORE_CREDENTIALS
);
833 } else if (agent
->compatibility
== NICE_COMPATIBILITY_MSN
) {
834 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
835 STUN_COMPATIBILITY_RFC3489
,
836 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
837 STUN_AGENT_USAGE_FORCE_VALIDATER
);
838 } else if (agent
->compatibility
== NICE_COMPATIBILITY_WLM2009
) {
839 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
840 STUN_COMPATIBILITY_WLM2009
,
841 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
842 STUN_AGENT_USAGE_USE_FINGERPRINT
);
844 stun_agent_init (&agent
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
845 STUN_COMPATIBILITY_RFC5389
,
846 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
847 STUN_AGENT_USAGE_USE_FINGERPRINT
);
849 stun_agent_set_software (&agent
->stun_agent
, agent
->software_attribute
);
853 case PROP_STUN_SERVER
:
854 agent
->stun_server_ip
= g_value_dup_string (value
);
857 case PROP_STUN_SERVER_PORT
:
858 agent
->stun_server_port
= g_value_get_uint (value
);
861 case PROP_CONTROLLING_MODE
:
862 agent
->controlling_mode
= g_value_get_boolean (value
);
866 agent
->full_mode
= g_value_get_boolean (value
);
869 case PROP_STUN_PACING_TIMER
:
870 agent
->timer_ta
= g_value_get_uint (value
);
873 case PROP_MAX_CONNECTIVITY_CHECKS
:
874 agent
->max_conn_checks
= g_value_get_uint (value
);
878 agent
->proxy_ip
= g_value_dup_string (value
);
881 case PROP_PROXY_PORT
:
882 agent
->proxy_port
= g_value_get_uint (value
);
885 case PROP_PROXY_TYPE
:
886 agent
->proxy_type
= g_value_get_uint (value
);
889 case PROP_PROXY_USERNAME
:
890 agent
->proxy_username
= g_value_dup_string (value
);
893 case PROP_PROXY_PASSWORD
:
894 agent
->proxy_password
= g_value_dup_string (value
);
897 case PROP_UPNP_TIMEOUT
:
899 agent
->upnp_timeout
= g_value_get_uint (value
);
905 agent
->upnp_enabled
= g_value_get_boolean (value
);
910 agent
->reliable
= g_value_get_boolean (value
);
914 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
922 static void priv_destroy_component_tcp (Component
*component
)
924 if (component
->tcp_clock
) {
925 g_source_destroy (component
->tcp_clock
);
926 g_source_unref (component
->tcp_clock
);
927 component
->tcp_clock
= NULL
;
929 if (component
->tcp
) {
930 pseudo_tcp_socket_close (component
->tcp
, TRUE
);
931 g_object_unref (component
->tcp
);
932 component
->tcp
= NULL
;
934 if (component
->tcp_data
!= NULL
) {
935 g_slice_free (TcpUserData
, component
->tcp_data
);
936 component
->tcp_data
= NULL
;
940 static void priv_pseudo_tcp_error (NiceAgent
*agent
, Stream
*stream
,
941 Component
*component
)
943 if (component
->tcp
) {
944 agent_signal_component_state_change (agent
, stream
->id
,
945 component
->id
, NICE_COMPONENT_STATE_FAILED
);
946 priv_detach_stream_component (stream
, component
);
948 priv_destroy_component_tcp (component
);
952 adjust_tcp_clock (NiceAgent
*agent
, Stream
*stream
, Component
*component
);
956 pseudo_tcp_socket_opened (PseudoTcpSocket
*sock
, gpointer user_data
)
958 TcpUserData
*data
= (TcpUserData
*)user_data
;
959 NiceAgent
*agent
= data
->agent
;
960 Component
*component
= data
->component
;
961 Stream
*stream
= data
->stream
;
963 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket Opened", data
->agent
,
964 stream
->id
, component
->id
);
965 g_signal_emit (agent
, signals
[SIGNAL_RELIABLE_TRANSPORT_WRITABLE
], 0,
966 stream
->id
, component
->id
);
970 pseudo_tcp_socket_readable (PseudoTcpSocket
*sock
, gpointer user_data
)
972 TcpUserData
*data
= (TcpUserData
*)user_data
;
973 NiceAgent
*agent
= data
->agent
;
974 Component
*component
= data
->component
;
975 Stream
*stream
= data
->stream
;
976 gchar buf
[MAX_BUFFER_SIZE
];
979 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket readable", agent
,
980 stream
->id
, component
->id
);
982 component
->tcp_readable
= TRUE
;
984 g_object_add_weak_pointer (G_OBJECT (sock
), (gpointer
*)&sock
);
985 g_object_add_weak_pointer (G_OBJECT (agent
), (gpointer
*)&agent
);
988 if (component
->g_source_io_cb
)
989 len
= pseudo_tcp_socket_recv (sock
, buf
, sizeof(buf
));
994 gpointer data
= component
->data
;
995 gint sid
= stream
->id
;
996 gint cid
= component
->id
;
997 NiceAgentRecvFunc callback
= component
->g_source_io_cb
;
998 /* Unlock the agent before calling the callback */
1000 callback (agent
, sid
, cid
, len
, buf
, data
);
1003 nice_debug ("PseudoTCP socket got destroyed in readable callback!");
1006 } else if (len
< 0 &&
1007 pseudo_tcp_socket_get_error (sock
) != EWOULDBLOCK
) {
1009 priv_pseudo_tcp_error (agent
, stream
, component
);
1010 } else if (len
< 0 &&
1011 pseudo_tcp_socket_get_error (sock
) == EWOULDBLOCK
){
1012 component
->tcp_readable
= FALSE
;
1017 adjust_tcp_clock (agent
, stream
, component
);
1018 g_object_remove_weak_pointer (G_OBJECT (agent
), (gpointer
*)&agent
);
1020 nice_debug ("Not calling adjust_tcp_clock.. agent got destroyed!");
1023 g_object_remove_weak_pointer (G_OBJECT (sock
), (gpointer
*)&sock
);
1027 pseudo_tcp_socket_writable (PseudoTcpSocket
*sock
, gpointer user_data
)
1029 TcpUserData
*data
= (TcpUserData
*)user_data
;
1030 NiceAgent
*agent
= data
->agent
;
1031 Component
*component
= data
->component
;
1032 Stream
*stream
= data
->stream
;
1034 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket writable", data
->agent
,
1035 data
->stream
->id
, data
->component
->id
);
1036 g_signal_emit (agent
, signals
[SIGNAL_RELIABLE_TRANSPORT_WRITABLE
], 0,
1037 stream
->id
, component
->id
);
1041 pseudo_tcp_socket_closed (PseudoTcpSocket
*sock
, guint32 err
,
1044 TcpUserData
*data
= (TcpUserData
*)user_data
;
1045 NiceAgent
*agent
= data
->agent
;
1046 Component
*component
= data
->component
;
1047 Stream
*stream
= data
->stream
;
1049 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket closed", agent
,
1050 stream
->id
, component
->id
);
1051 priv_pseudo_tcp_error (agent
, stream
, component
);
1055 static PseudoTcpWriteResult
1056 pseudo_tcp_socket_write_packet (PseudoTcpSocket
*sock
,
1057 const gchar
*buffer
, guint32 len
, gpointer user_data
)
1059 TcpUserData
*data
= (TcpUserData
*)user_data
;
1060 NiceAgent
*agent
= data
->agent
;
1061 Component
*component
= data
->component
;
1062 Stream
*stream
= data
->stream
;
1064 if (component
->selected_pair
.local
!= NULL
) {
1069 gchar tmpbuf
[INET6_ADDRSTRLEN
];
1070 nice_address_to_string (&component
->selected_pair
.remote
->addr
, tmpbuf
);
1072 nice_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", agent
,
1073 stream
->id
, component
->id
, len
, tmpbuf
,
1074 nice_address_get_port (&component
->selected_pair
.remote
->addr
));
1077 sock
= component
->selected_pair
.local
->sockptr
;
1078 addr
= &component
->selected_pair
.remote
->addr
;
1079 if (nice_socket_send (sock
, addr
, len
, buffer
)) {
1089 notify_pseudo_tcp_socket_clock (gpointer user_data
)
1091 TcpUserData
*data
= (TcpUserData
*)user_data
;
1092 Component
*component
= data
->component
;
1093 Stream
*stream
= data
->stream
;
1094 NiceAgent
*agent
= data
->agent
;
1098 if (g_source_is_destroyed (g_main_current_source ())) {
1099 nice_debug ("Source was destroyed. "
1100 "Avoided race condition in notify_pseudo_tcp_socket_clock");
1104 if (component
->tcp_clock
) {
1105 g_source_destroy (component
->tcp_clock
);
1106 g_source_unref (component
->tcp_clock
);
1107 component
->tcp_clock
= NULL
;
1110 pseudo_tcp_socket_notify_clock (component
->tcp
);
1111 adjust_tcp_clock (agent
, stream
, component
);
1119 adjust_tcp_clock (NiceAgent
*agent
, Stream
*stream
, Component
*component
)
1122 if (component
->tcp
) {
1123 if (pseudo_tcp_socket_get_next_clock (component
->tcp
, &timeout
)) {
1124 if (component
->tcp_clock
) {
1125 g_source_destroy (component
->tcp_clock
);
1126 g_source_unref (component
->tcp_clock
);
1127 component
->tcp_clock
= NULL
;
1129 component
->tcp_clock
= agent_timeout_add_with_context (agent
,
1130 timeout
, notify_pseudo_tcp_socket_clock
, component
->tcp_data
);
1132 nice_debug ("Agent %p: component %d pseudo tcp socket should be destroyed",
1133 agent
, component
->id
);
1134 priv_pseudo_tcp_error (agent
, stream
, component
);
1140 void agent_gathering_done (NiceAgent
*agent
)
1143 GSList
*i
, *j
, *k
, *l
, *m
;
1145 for (i
= agent
->streams
; i
; i
= i
->next
) {
1146 Stream
*stream
= i
->data
;
1147 for (j
= stream
->components
; j
; j
= j
->next
) {
1148 Component
*component
= j
->data
;
1150 for (k
= component
->local_candidates
; k
; k
= k
->next
) {
1151 NiceCandidate
*local_candidate
= k
->data
;
1153 gchar tmpbuf
[INET6_ADDRSTRLEN
];
1154 nice_address_to_string (&local_candidate
->addr
, tmpbuf
);
1155 nice_debug ("Agent %p: gathered local candidate : [%s]:%u"
1156 " for s%d/c%d. U/P '%s'/'%s'", agent
,
1157 tmpbuf
, nice_address_get_port (&local_candidate
->addr
),
1158 local_candidate
->stream_id
, local_candidate
->component_id
,
1159 local_candidate
->username
, local_candidate
->password
);
1161 for (l
= component
->remote_candidates
; l
; l
= l
->next
) {
1162 NiceCandidate
*remote_candidate
= l
->data
;
1164 for (m
= stream
->conncheck_list
; m
; m
= m
->next
) {
1165 CandidateCheckPair
*p
= m
->data
;
1167 if (p
->local
== local_candidate
&& p
->remote
== remote_candidate
)
1171 conn_check_add_for_candidate (agent
, stream
->id
, component
, remote_candidate
);
1179 if (agent
->discovery_timer_source
== NULL
&&
1180 agent
->upnp_timer_source
== NULL
) {
1181 agent_signal_gathering_done (agent
);
1184 agent_signal_gathering_done (agent
);
1188 void agent_signal_gathering_done (NiceAgent
*agent
)
1192 for (i
= agent
->streams
; i
; i
= i
->next
) {
1193 Stream
*stream
= i
->data
;
1194 if (stream
->gathering
) {
1195 stream
->gathering
= FALSE
;
1196 g_signal_emit (agent
, signals
[SIGNAL_CANDIDATE_GATHERING_DONE
], 0, stream
->id
);
1201 void agent_signal_initial_binding_request_received (NiceAgent
*agent
, Stream
*stream
)
1203 if (stream
->initial_binding_request_received
!= TRUE
) {
1204 stream
->initial_binding_request_received
= TRUE
;
1205 g_signal_emit (agent
, signals
[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED
], 0, stream
->id
);
1209 void agent_signal_new_selected_pair (NiceAgent
*agent
, guint stream_id
, guint component_id
, const gchar
*local_foundation
, const gchar
*remote_foundation
)
1211 Component
*component
;
1216 if (!agent_find_component (agent
, stream_id
, component_id
,
1217 &stream
, &component
))
1220 if (component
->selected_pair
.local
->type
== NICE_CANDIDATE_TYPE_RELAYED
) {
1221 nice_turn_socket_set_peer (component
->selected_pair
.local
->sockptr
,
1222 &component
->selected_pair
.remote
->addr
);
1225 if (component
->tcp
) {
1226 pseudo_tcp_socket_connect (component
->tcp
);
1227 pseudo_tcp_socket_notify_mtu (component
->tcp
, MAX_TCP_MTU
);
1228 adjust_tcp_clock (agent
, stream
, component
);
1229 } else if(agent
->reliable
) {
1230 nice_debug ("New selected pair received when pseudo tcp socket in error");
1234 lf_copy
= g_strdup (local_foundation
);
1235 rf_copy
= g_strdup (remote_foundation
);
1237 g_signal_emit (agent
, signals
[SIGNAL_NEW_SELECTED_PAIR
], 0,
1238 stream_id
, component_id
, lf_copy
, rf_copy
);
1244 void agent_signal_new_candidate (NiceAgent
*agent
, NiceCandidate
*candidate
)
1246 g_signal_emit (agent
, signals
[SIGNAL_NEW_CANDIDATE
], 0,
1247 candidate
->stream_id
,
1248 candidate
->component_id
,
1249 candidate
->foundation
);
1252 void agent_signal_new_remote_candidate (NiceAgent
*agent
, NiceCandidate
*candidate
)
1254 g_signal_emit (agent
, signals
[SIGNAL_NEW_REMOTE_CANDIDATE
], 0,
1255 candidate
->stream_id
,
1256 candidate
->component_id
,
1257 candidate
->foundation
);
1260 void agent_signal_component_state_change (NiceAgent
*agent
, guint stream_id
, guint component_id
, NiceComponentState state
)
1262 Component
*component
;
1265 if (!agent_find_component (agent
, stream_id
, component_id
,
1266 &stream
, &component
))
1269 if (agent
->reliable
&& component
->tcp
== NULL
&&
1270 state
!= NICE_COMPONENT_STATE_FAILED
) {
1271 nice_debug ("Agent %p: not changing component state for s%d:%d to %d "
1272 "because pseudo tcp socket does not exist in reliable mode", agent
,
1273 stream
->id
, component
->id
, state
);
1277 if (component
->state
!= state
&& state
< NICE_COMPONENT_STATE_LAST
) {
1278 nice_debug ("Agent %p : stream %u component %u STATE-CHANGE %u -> %u.", agent
,
1279 stream_id
, component_id
, component
->state
, state
);
1281 component
->state
= state
;
1283 g_signal_emit (agent
, signals
[SIGNAL_COMPONENT_STATE_CHANGED
], 0,
1284 stream_id
, component_id
, state
);
1289 agent_candidate_pair_priority (NiceAgent
*agent
, NiceCandidate
*local
, NiceCandidate
*remote
)
1291 if (agent
->controlling_mode
)
1292 return nice_candidate_pair_priority (local
->priority
, remote
->priority
);
1294 return nice_candidate_pair_priority (remote
->priority
, local
->priority
);
1298 priv_add_new_candidate_discovery_stun (NiceAgent
*agent
,
1299 NiceSocket
*socket
, NiceAddress server
,
1300 Stream
*stream
, guint component_id
)
1302 CandidateDiscovery
*cdisco
;
1303 GSList
*modified_list
;
1305 /* note: no need to check for redundant candidates, as this is
1306 * done later on in the process */
1308 cdisco
= g_slice_new0 (CandidateDiscovery
);
1310 modified_list
= g_slist_append (agent
->discovery_list
, cdisco
);
1312 if (modified_list
) {
1313 cdisco
->type
= NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE
;
1314 cdisco
->nicesock
= socket
;
1315 cdisco
->server
= server
;
1316 cdisco
->stream
= stream
;
1317 cdisco
->component
= stream_find_component_by_id (stream
, component_id
);
1318 cdisco
->agent
= agent
;
1319 stun_agent_init (&cdisco
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
1320 STUN_COMPATIBILITY_RFC3489
, 0);
1322 nice_debug ("Agent %p : Adding new srv-rflx candidate discovery %p\n",
1324 agent
->discovery_list
= modified_list
;
1325 ++agent
->discovery_unsched_items
;
1335 priv_add_new_candidate_discovery_turn (NiceAgent
*agent
,
1336 NiceSocket
*socket
, TurnServer
*turn
,
1337 Stream
*stream
, guint component_id
)
1339 CandidateDiscovery
*cdisco
;
1340 GSList
*modified_list
;
1341 GSList
*socket_modified_list
;
1343 /* note: no need to check for redundant candidates, as this is
1344 * done later on in the process */
1346 cdisco
= g_slice_new0 (CandidateDiscovery
);
1348 modified_list
= g_slist_append (agent
->discovery_list
, cdisco
);
1350 if (modified_list
) {
1351 Component
*component
= stream_find_component_by_id (stream
, component_id
);
1353 cdisco
->type
= NICE_CANDIDATE_TYPE_RELAYED
;
1355 if (turn
->type
== NICE_RELAY_TYPE_TURN_UDP
) {
1356 if (agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
) {
1357 NiceAddress addr
= socket
->addr
;
1358 NiceSocket
*new_socket
;
1359 nice_address_set_port (&addr
, 0);
1361 new_socket
= nice_udp_bsd_socket_new (&addr
);
1363 _priv_set_socket_tos (agent
, new_socket
, stream
->tos
);
1364 agent_attach_stream_component_socket (agent
, stream
,
1365 component
, new_socket
);
1366 socket_modified_list
= g_slist_append (component
->sockets
, new_socket
);
1367 if (socket_modified_list
) {
1368 /* success: store a pointer to the sockaddr */
1369 component
->sockets
= socket_modified_list
;
1370 socket
= new_socket
;
1372 nice_socket_free (new_socket
);
1376 cdisco
->nicesock
= socket
;
1378 NiceAddress proxy_server
;
1381 if (agent
->proxy_type
!= NICE_PROXY_TYPE_NONE
&&
1382 agent
->proxy_ip
!= NULL
&&
1383 nice_address_set_from_string (&proxy_server
, agent
->proxy_ip
)) {
1384 nice_address_set_port (&proxy_server
, agent
->proxy_port
);
1385 socket
= nice_tcp_bsd_socket_new (agent
, component
->ctx
, &proxy_server
);
1388 _priv_set_socket_tos (agent
, socket
, stream
->tos
);
1389 if (agent
->proxy_type
== NICE_PROXY_TYPE_SOCKS5
) {
1390 socket
= nice_socks5_socket_new (socket
, &turn
->server
,
1391 agent
->proxy_username
, agent
->proxy_password
);
1392 } else if (agent
->proxy_type
== NICE_PROXY_TYPE_HTTP
){
1393 socket
= nice_http_socket_new (socket
, &turn
->server
,
1394 agent
->proxy_username
, agent
->proxy_password
);
1396 nice_socket_free (socket
);
1402 if (socket
== NULL
) {
1403 socket
= nice_tcp_bsd_socket_new (agent
, component
->ctx
, &turn
->server
);
1404 _priv_set_socket_tos (agent
, socket
, stream
->tos
);
1406 if (turn
->type
== NICE_RELAY_TYPE_TURN_TLS
&&
1407 agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
) {
1408 socket
= nice_pseudossl_socket_new (agent
, socket
);
1410 cdisco
->nicesock
= nice_tcp_turn_socket_new (agent
, socket
,
1411 agent_to_turn_socket_compatibility (agent
));
1413 if (!cdisco
->nicesock
) {
1414 agent
->discovery_list
= g_slist_remove (modified_list
, cdisco
);
1415 g_slice_free (CandidateDiscovery
, cdisco
);
1419 agent_attach_stream_component_socket (agent
, stream
,
1420 component
, cdisco
->nicesock
);
1421 socket_modified_list
= g_slist_append (component
->sockets
, cdisco
->nicesock
);
1422 if (socket_modified_list
) {
1423 /* success: store a pointer to the sockaddr */
1424 component
->sockets
= socket_modified_list
;
1427 cdisco
->turn
= turn
;
1428 cdisco
->server
= turn
->server
;
1430 cdisco
->stream
= stream
;
1431 cdisco
->component
= stream_find_component_by_id (stream
, component_id
);
1432 cdisco
->agent
= agent
;
1434 if (agent
->compatibility
== NICE_COMPATIBILITY_GOOGLE
) {
1435 stun_agent_init (&cdisco
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
1436 STUN_COMPATIBILITY_RFC3489
,
1437 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
|
1438 STUN_AGENT_USAGE_IGNORE_CREDENTIALS
);
1439 } else if (agent
->compatibility
== NICE_COMPATIBILITY_MSN
||
1440 agent
->compatibility
== NICE_COMPATIBILITY_WLM2009
) {
1441 stun_agent_init (&cdisco
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
1442 STUN_COMPATIBILITY_RFC3489
,
1443 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
);
1445 stun_agent_init (&cdisco
->stun_agent
, STUN_ALL_KNOWN_ATTRIBUTES
,
1446 STUN_COMPATIBILITY_RFC5389
,
1447 STUN_AGENT_USAGE_ADD_SOFTWARE
|
1448 STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS
);
1450 stun_agent_set_software (&cdisco
->stun_agent
, agent
->software_attribute
);
1452 nice_debug ("Agent %p : Adding new relay-rflx candidate discovery %p\n",
1454 agent
->discovery_list
= modified_list
;
1455 ++agent
->discovery_unsched_items
;
1464 NICEAPI_EXPORT guint
1465 nice_agent_add_stream (
1470 GSList
*modified_list
= NULL
;
1475 stream
= stream_new (n_components
);
1477 modified_list
= g_slist_append (agent
->streams
, stream
);
1478 if (modified_list
) {
1479 stream
->id
= agent
->next_stream_id
++;
1480 nice_debug ("Agent %p : allocating stream id %u (%p)", agent
, stream
->id
, stream
);
1481 if (agent
->reliable
) {
1482 nice_debug ("Agent %p : reliable stream", agent
);
1483 for (i
= 0; i
< n_components
; i
++) {
1484 Component
*component
= stream_find_component_by_id (stream
, i
+ 1);
1486 TcpUserData
*data
= g_slice_new0 (TcpUserData
);
1487 PseudoTcpCallbacks tcp_callbacks
= {data
,
1488 pseudo_tcp_socket_opened
,
1489 pseudo_tcp_socket_readable
,
1490 pseudo_tcp_socket_writable
,
1491 pseudo_tcp_socket_closed
,
1492 pseudo_tcp_socket_write_packet
};
1493 data
->agent
= agent
;
1494 data
->stream
= stream
;
1495 data
->component
= component
;
1496 component
->tcp_data
= data
;
1497 component
->tcp
= pseudo_tcp_socket_new (0, &tcp_callbacks
);
1498 adjust_tcp_clock (agent
, stream
, component
);
1499 nice_debug ("Agent %p: Create Pseudo Tcp Socket for component %d",
1502 nice_debug ("Agent %p: couldn't find component %d", agent
, i
+1);
1507 stream_initialize_credentials (stream
, agent
->rng
);
1509 agent
->streams
= modified_list
;
1512 stream_free (stream
);
1522 NICEAPI_EXPORT gboolean
1523 nice_agent_set_relay_info(NiceAgent
*agent
,
1524 guint stream_id
, guint component_id
,
1525 const gchar
*server_ip
, guint server_port
,
1526 const gchar
*username
, const gchar
*password
,
1530 Component
*component
= NULL
;
1532 g_return_val_if_fail (server_ip
, FALSE
);
1533 g_return_val_if_fail (server_port
, FALSE
);
1534 g_return_val_if_fail (username
, FALSE
);
1535 g_return_val_if_fail (password
, FALSE
);
1536 g_return_val_if_fail (type
<= NICE_PROXY_TYPE_LAST
, FALSE
);
1540 if (agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
)) {
1541 TurnServer
*turn
= g_slice_new0 (TurnServer
);
1542 nice_address_init (&turn
->server
);
1544 if (nice_address_set_from_string (&turn
->server
, server_ip
)) {
1545 nice_address_set_port (&turn
->server
, server_port
);
1547 g_slice_free (TurnServer
, turn
);
1553 turn
->username
= g_strdup (username
);
1554 turn
->password
= g_strdup (password
);
1557 nice_debug ("Agent %p: added relay server [%s]:%d of type %d", agent
,
1558 server_ip
, server_port
, type
);
1560 component
->turn_servers
= g_list_append (component
->turn_servers
, turn
);
1569 static gboolean
priv_upnp_timeout_cb (gpointer user_data
)
1571 NiceAgent
*agent
= (NiceAgent
*)user_data
;
1576 if (g_source_is_destroyed (g_main_current_source ())) {
1581 nice_debug ("Agent %p : UPnP port mapping timed out", agent
);
1583 for (i
= agent
->upnp_mapping
; i
; i
= i
->next
) {
1584 NiceAddress
*a
= i
->data
;
1585 nice_address_free (a
);
1587 g_slist_free (agent
->upnp_mapping
);
1588 agent
->upnp_mapping
= NULL
;
1590 if (agent
->upnp_timer_source
!= NULL
) {
1591 g_source_destroy (agent
->upnp_timer_source
);
1592 g_source_unref (agent
->upnp_timer_source
);
1593 agent
->upnp_timer_source
= NULL
;
1596 agent_gathering_done (agent
);
1602 static void _upnp_mapped_external_port (GUPnPSimpleIgd
*self
, gchar
*proto
,
1603 gchar
*external_ip
, gchar
*replaces_external_ip
, guint external_port
,
1604 gchar
*local_ip
, guint local_port
, gchar
*description
, gpointer user_data
)
1606 NiceAgent
*agent
= (NiceAgent
*)user_data
;
1607 NiceAddress localaddr
;
1608 NiceAddress externaddr
;
1614 nice_debug ("Agent %p : Sucessfully mapped %s:%d to %s:%d", agent
, local_ip
,
1615 local_port
, external_ip
, external_port
);
1617 if (!nice_address_set_from_string (&localaddr
, local_ip
))
1619 nice_address_set_port (&localaddr
, local_port
);
1621 for (i
= agent
->upnp_mapping
; i
; i
= i
->next
) {
1622 NiceAddress
*addr
= i
->data
;
1623 if (nice_address_equal (&localaddr
, addr
)) {
1624 agent
->upnp_mapping
= g_slist_remove (agent
->upnp_mapping
, addr
);
1625 nice_address_free (addr
);
1630 if (!nice_address_set_from_string (&externaddr
, external_ip
))
1632 nice_address_set_port (&externaddr
, external_port
);
1634 for (i
= agent
->streams
; i
; i
= i
->next
) {
1635 Stream
*stream
= i
->data
;
1636 for (j
= stream
->components
; j
; j
= j
->next
) {
1637 Component
*component
= j
->data
;
1638 for (k
= component
->local_candidates
; k
; k
= k
->next
) {
1639 NiceCandidate
*local_candidate
= k
->data
;
1641 if (nice_address_equal (&localaddr
, &local_candidate
->base_addr
)) {
1642 discovery_add_server_reflexive_candidate (
1647 local_candidate
->sockptr
);
1655 if (g_slist_length (agent
->upnp_mapping
)) {
1656 if (agent
->upnp_timer_source
!= NULL
) {
1657 g_source_destroy (agent
->upnp_timer_source
);
1658 g_source_unref (agent
->upnp_timer_source
);
1659 agent
->upnp_timer_source
= NULL
;
1661 agent_gathering_done (agent
);
1667 static void _upnp_error_mapping_port (GUPnPSimpleIgd
*self
, GError
*error
,
1668 gchar
*proto
, guint external_port
, gchar
*local_ip
, guint local_port
,
1669 gchar
*description
, gpointer user_data
)
1671 NiceAgent
*agent
= (NiceAgent
*)user_data
;
1672 NiceAddress localaddr
;
1677 nice_debug ("Agent %p : Error mapping %s:%d to %d (%d) : %s", agent
, local_ip
,
1678 local_port
, external_port
, error
->domain
, error
->message
);
1679 if (nice_address_set_from_string (&localaddr
, local_ip
)) {
1680 nice_address_set_port (&localaddr
, local_port
);
1682 for (i
= agent
->upnp_mapping
; i
; i
= i
->next
) {
1683 NiceAddress
*addr
= i
->data
;
1684 if (nice_address_equal (&localaddr
, addr
)) {
1685 agent
->upnp_mapping
= g_slist_remove (agent
->upnp_mapping
, addr
);
1686 nice_address_free (addr
);
1691 if (g_slist_length (agent
->upnp_mapping
)) {
1692 if (agent
->upnp_timer_source
!= NULL
) {
1693 g_source_destroy (agent
->upnp_timer_source
);
1694 g_source_unref (agent
->upnp_timer_source
);
1695 agent
->upnp_timer_source
= NULL
;
1697 agent_gathering_done (agent
);
1707 nice_agent_gather_candidates (
1717 stream
= agent_find_stream (agent
, stream_id
);
1718 if (stream
== NULL
) {
1722 nice_debug ("Agent %p : In %s mode, starting candidate gathering.", agent
,
1723 agent
->full_mode
? "ICE-FULL" : "ICE-LITE");
1726 priv_free_upnp (agent
);
1728 if (agent
->upnp_enabled
) {
1729 agent
->upnp
= gupnp_simple_igd_thread_new ();
1731 agent
->upnp_timer_source
= agent_timeout_add_with_context (agent
,
1732 agent
->upnp_timeout
, priv_upnp_timeout_cb
, agent
);
1735 g_signal_connect (agent
->upnp
, "mapped-external-port",
1736 G_CALLBACK (_upnp_mapped_external_port
), agent
);
1737 g_signal_connect (agent
->upnp
, "error-mapping-port",
1738 G_CALLBACK (_upnp_error_mapping_port
), agent
);
1740 nice_debug ("Agent %p : Error creating UPnP Simple IGD agent", agent
);
1743 nice_debug ("Agent %p : UPnP property Disabled", agent
);
1746 nice_debug ("Agent %p : libnice compiled without UPnP support", agent
);
1749 /* if no local addresses added, generate them ourselves */
1750 if (agent
->local_addresses
== NULL
) {
1751 GList
*addresses
= nice_interfaces_get_local_ips (FALSE
);
1754 for (item
= addresses
; item
; item
= g_list_next (item
)) {
1755 NiceAddress
*addr
= nice_address_new ();
1757 if (nice_address_set_from_string (addr
, item
->data
)) {
1758 nice_agent_add_local_address (agent
, addr
);
1760 nice_address_free (addr
);
1763 g_list_foreach (addresses
, (GFunc
) g_free
, NULL
);
1764 g_list_free (addresses
);
1767 /* generate a local host candidate for each local address */
1768 for (i
= agent
->local_addresses
; i
; i
= i
->next
){
1769 NiceAddress
*addr
= i
->data
;
1770 NiceCandidate
*host_candidate
;
1773 gchar local_ip
[NICE_ADDRESS_STRING_LEN
];
1774 nice_address_to_string (addr
, local_ip
);
1777 for (n
= 0; n
< stream
->n_components
; n
++) {
1778 Component
*component
= stream_find_component_by_id (stream
, n
+ 1);
1780 if (agent
->reliable
&& component
->tcp
== NULL
) {
1781 nice_debug ("Agent %p: not gathering candidates for s%d:%d because "
1782 "pseudo tcp socket does not exist in reliable mode", agent
,
1783 stream
->id
, component
->id
);
1787 host_candidate
= discovery_add_local_host_candidate (agent
, stream
->id
,
1790 if (!host_candidate
) {
1791 g_error ("No host candidate??");
1796 if (agent
->upnp_enabled
) {
1797 NiceAddress
*addr
= nice_address_dup (&host_candidate
->base_addr
);
1798 nice_debug ("Agent %p: Adding UPnP port %s:%d", agent
, local_ip
,
1799 nice_address_get_port (&host_candidate
->base_addr
));
1800 gupnp_simple_igd_add_port (GUPNP_SIMPLE_IGD (agent
->upnp
), "UDP",
1801 0, local_ip
, nice_address_get_port (&host_candidate
->base_addr
),
1803 agent
->upnp_mapping
= g_slist_prepend (agent
->upnp_mapping
, addr
);
1807 if (agent
->full_mode
&&
1808 agent
->stun_server_ip
) {
1809 NiceAddress stun_server
;
1810 if (nice_address_set_from_string (&stun_server
, agent
->stun_server_ip
)) {
1812 nice_address_set_port (&stun_server
, agent
->stun_server_port
);
1815 priv_add_new_candidate_discovery_stun (agent
,
1816 host_candidate
->sockptr
,
1822 /* note: memory allocation failure, return error */
1823 g_error ("Memory allocation failure?");
1828 if (agent
->full_mode
&& component
) {
1831 for (item
= component
->turn_servers
; item
; item
= item
->next
) {
1832 TurnServer
*turn
= item
->data
;
1835 priv_add_new_candidate_discovery_turn (agent
,
1836 host_candidate
->sockptr
,
1842 /* note: memory allocation failure, return error */
1843 g_error ("Memory allocation failure?");
1850 stream
->gathering
= TRUE
;
1853 /* note: no async discoveries pending, signal that we are ready */
1854 if (agent
->discovery_unsched_items
== 0) {
1855 nice_debug ("Agent %p: Candidate gathering FINISHED, no scheduled items.",
1857 agent_gathering_done (agent
);
1859 g_assert (agent
->discovery_list
);
1860 discovery_schedule (agent
);
1868 static void priv_free_upnp (NiceAgent
*agent
)
1874 g_object_unref (agent
->upnp
);
1878 for (i
= agent
->upnp_mapping
; i
; i
= i
->next
) {
1879 NiceAddress
*a
= i
->data
;
1880 nice_address_free (a
);
1882 g_slist_free (agent
->upnp_mapping
);
1883 agent
->upnp_mapping
= NULL
;
1885 if (agent
->upnp_timer_source
!= NULL
) {
1886 g_source_destroy (agent
->upnp_timer_source
);
1887 g_source_unref (agent
->upnp_timer_source
);
1888 agent
->upnp_timer_source
= NULL
;
1893 static void priv_remove_keepalive_timer (NiceAgent
*agent
)
1895 if (agent
->keepalive_timer_source
!= NULL
) {
1896 g_source_destroy (agent
->keepalive_timer_source
);
1897 g_source_unref (agent
->keepalive_timer_source
);
1898 agent
->keepalive_timer_source
= NULL
;
1903 nice_agent_remove_stream (
1907 /* note that streams/candidates can be in use by other threads */
1912 stream
= agent_find_stream (agent
, stream_id
);
1918 /* note: remove items with matching stream_ids from both lists */
1919 conn_check_prune_stream (agent
, stream
);
1920 discovery_prune_stream (agent
, stream_id
);
1921 refresh_prune_stream (agent
, stream_id
);
1923 /* remove the stream itself */
1924 agent
->streams
= g_slist_remove (agent
->streams
, stream
);
1925 stream_free (stream
);
1927 if (!agent
->streams
)
1928 priv_remove_keepalive_timer (agent
);
1934 NICEAPI_EXPORT gboolean
1935 nice_agent_add_local_address (NiceAgent
*agent
, NiceAddress
*addr
)
1938 GSList
*modified_list
;
1939 gboolean ret
= FALSE
;
1943 dup
= nice_address_dup (addr
);
1944 nice_address_set_port (dup
, 0);
1945 modified_list
= g_slist_append (agent
->local_addresses
, dup
);
1946 if (modified_list
) {
1947 agent
->local_addresses
= modified_list
;
1958 static gboolean
priv_add_remote_candidate (
1962 NiceCandidateType type
,
1963 const NiceAddress
*addr
,
1964 const NiceAddress
*base_addr
,
1965 NiceCandidateTransport transport
,
1967 const gchar
*username
,
1968 const gchar
*password
,
1969 const gchar
*foundation
)
1971 Component
*component
;
1972 NiceCandidate
*candidate
;
1973 gboolean error_flag
= FALSE
;
1975 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
1978 /* step: check whether the candidate already exists */
1979 candidate
= component_find_remote_candidate(component
, addr
, transport
);
1982 gchar tmpbuf
[INET6_ADDRSTRLEN
];
1983 nice_address_to_string (addr
, tmpbuf
);
1984 nice_debug ("Agent %p : Updating existing remote candidate with addr [%s]:%u"
1985 " for s%d/c%d. U/P '%s'/'%s' prio: %u", agent
, tmpbuf
,
1986 nice_address_get_port (addr
), stream_id
, component_id
,
1987 username
, password
, priority
);
1989 /* case 1: an existing candidate, update the attributes */
1990 candidate
->type
= type
;
1992 candidate
->base_addr
= *base_addr
;
1993 candidate
->priority
= priority
;
1995 g_strlcpy(candidate
->foundation
, foundation
,
1996 NICE_CANDIDATE_MAX_FOUNDATION
);
1997 /* note: username and password must remain the same during
1998 * a session; see sect 9.1.2 in ICE ID-19 */
2000 /* note: however, the user/pass in ID-19 is global, if the user/pass
2001 * are set in the candidate here, it means they need to be updated...
2002 * this is essential to overcome a race condition where we might receive
2003 * a valid binding request from a valid candidate that wasn't yet added to
2004 * our list of candidates.. this 'update' will make the peer-rflx a
2005 * server-rflx/host candidate again and restore that user/pass it needed
2006 * to have in the first place */
2008 g_free (candidate
->username
);
2009 candidate
->username
= g_strdup (username
);
2012 g_free (candidate
->password
);
2013 candidate
->password
= g_strdup (password
);
2015 if (conn_check_add_for_candidate (agent
, stream_id
, component
, candidate
) < 0)
2019 /* case 2: add a new candidate */
2021 candidate
= nice_candidate_new (type
);
2023 GSList
*modified_list
= g_slist_append (component
->remote_candidates
, candidate
);
2024 if (modified_list
) {
2025 component
->remote_candidates
= modified_list
;
2027 candidate
->stream_id
= stream_id
;
2028 candidate
->component_id
= component_id
;
2030 candidate
->type
= type
;
2032 candidate
->addr
= *addr
;
2034 gchar tmpbuf
[INET6_ADDRSTRLEN
] = {0};
2036 nice_address_to_string (addr
, tmpbuf
);
2037 nice_debug ("Agent %p : Adding remote candidate with addr [%s]:%u"
2038 " for s%d/c%d. U/P '%s'/'%s' prio: %u", agent
, tmpbuf
,
2039 addr
? nice_address_get_port (addr
) : 0, stream_id
, component_id
,
2040 username
, password
, priority
);
2044 candidate
->base_addr
= *base_addr
;
2046 candidate
->transport
= transport
;
2047 candidate
->priority
= priority
;
2048 candidate
->username
= g_strdup (username
);
2049 candidate
->password
= g_strdup (password
);
2052 g_strlcpy (candidate
->foundation
, foundation
,
2053 NICE_CANDIDATE_MAX_FOUNDATION
);
2055 if (conn_check_add_for_candidate (agent
, stream_id
, component
, candidate
) < 0)
2058 else /* memory alloc error: list insert */
2061 else /* memory alloc error: candidate creation */
2067 nice_candidate_free (candidate
);
2074 NICEAPI_EXPORT gboolean
2075 nice_agent_set_remote_credentials (
2078 const gchar
*ufrag
, const gchar
*pwd
)
2081 gboolean ret
= FALSE
;
2085 stream
= agent_find_stream (agent
, stream_id
);
2086 /* note: oddly enough, ufrag and pwd can be empty strings */
2087 if (stream
&& ufrag
&& pwd
) {
2089 g_strlcpy (stream
->remote_ufrag
, ufrag
, NICE_STREAM_MAX_UFRAG
);
2090 g_strlcpy (stream
->remote_password
, pwd
, NICE_STREAM_MAX_PWD
);
2102 NICEAPI_EXPORT gboolean
2103 nice_agent_get_local_credentials (
2106 gchar
**ufrag
, gchar
**pwd
)
2109 gboolean ret
= TRUE
;
2113 stream
= agent_find_stream (agent
, stream_id
);
2114 if (stream
== NULL
) {
2118 if (!ufrag
|| !pwd
) {
2122 *ufrag
= g_strdup (stream
->local_ufrag
);
2123 *pwd
= g_strdup (stream
->local_password
);
2133 nice_agent_set_remote_candidates (NiceAgent
*agent
, guint stream_id
, guint component_id
, const GSList
*candidates
)
2138 Component
*component
;
2140 nice_debug ("Agent %p: set_remote_candidates %d %d", agent
, stream_id
, component_id
);
2144 if (!agent_find_component (agent
, stream_id
, component_id
,
2145 &stream
, &component
)) {
2146 g_warning ("Could not find component %u in stream %u", component_id
,
2152 if (agent
->discovery_unsched_items
> 0 || stream
->gathering
) {
2153 nice_debug ("Agent %p: Remote candidates refused for stream %d because "
2154 "we are still gathering our own candidates", agent
, stream_id
);
2159 if (agent
->reliable
&& component
->tcp
== NULL
) {
2160 nice_debug ("Agent %p: not setting remote candidate for s%d:%d because "
2161 "pseudo tcp socket does not exist in reliable mode", agent
,
2162 stream
->id
, component
->id
);
2166 for (i
= candidates
; i
&& added
>= 0; i
= i
->next
) {
2167 NiceCandidate
*d
= (NiceCandidate
*) i
->data
;
2169 if (nice_address_is_valid (&d
->addr
) == TRUE
) {
2171 priv_add_remote_candidate (agent
,
2187 conn_check_remote_candidates_set(agent
);
2190 gboolean res
= conn_check_schedule_next (agent
);
2192 nice_debug ("Agent %p : Warning: unable to schedule any conn checks!", agent
);
2205 Component
*component
,
2214 len
= nice_socket_recv (socket
, &from
, buf_len
, buf
);
2221 gchar tmpbuf
[INET6_ADDRSTRLEN
];
2222 nice_address_to_string (&from
, tmpbuf
);
2223 nice_debug ("Agent %p : Packet received on local socket %u from [%s]:%u (%u octets).", agent
,
2224 socket
->fileno
, tmpbuf
, nice_address_get_port (&from
), len
);
2229 if ((guint
)len
> buf_len
)
2231 /* buffer is not big enough to accept this packet */
2232 /* XXX: test this case */
2236 for (item
= component
->turn_servers
; item
; item
= g_list_next (item
)) {
2237 TurnServer
*turn
= item
->data
;
2238 if (nice_address_equal (&from
, &turn
->server
)) {
2241 nice_debug ("Agent %p : Packet received from TURN server candidate.",
2244 for (i
= component
->local_candidates
; i
; i
= i
->next
) {
2245 NiceCandidate
*cand
= i
->data
;
2246 if (cand
->type
== NICE_CANDIDATE_TYPE_RELAYED
&&
2247 cand
->stream_id
== stream
->id
&&
2248 cand
->component_id
== component
->id
) {
2249 len
= nice_turn_socket_parse_recv (cand
->sockptr
, &socket
,
2250 &from
, len
, buf
, &from
, buf
, len
);
2257 agent
->media_after_tick
= TRUE
;
2259 if (stun_message_validate_buffer_length ((uint8_t *) buf
, (size_t) len
) != len
)
2260 /* If the retval is no 0, its not a valid stun packet, probably data */
2264 if (conn_check_handle_inbound_stun (agent
, stream
, component
, socket
,
2266 /* handled STUN message*/
2269 /* unhandled STUN, pass to client */
2283 Component
*component
;
2288 if (!agent_find_component (agent
, stream_id
, component_id
,
2289 &stream
, &component
)) {
2293 if (component
->tcp
!= NULL
) {
2294 ret
= pseudo_tcp_socket_send (component
->tcp
, buf
, len
);
2295 adjust_tcp_clock (agent
, stream
, component
);
2298 pseudo_tcp_socket_get_error (component->tcp) != EWOULDBLOCK) {
2301 /* In case of -1, the error is either EWOULDBLOCK or ENOTCONN, which both
2302 need the user to wait for the reliable-transport-writable signal */
2303 } else if(agent
->reliable
) {
2304 nice_debug ("Trying to send on a pseudo tcp FAILED component");
2306 } else if (component
->selected_pair
.local
!= NULL
) {
2311 gchar tmpbuf
[INET6_ADDRSTRLEN
];
2312 nice_address_to_string (&component
->selected_pair
.remote
->addr
, tmpbuf
);
2314 nice_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", agent
, stream_id
, component_id
,
2316 nice_address_get_port (&component
->selected_pair
.remote
->addr
));
2319 sock
= component
->selected_pair
.local
->sockptr
;
2320 addr
= &component
->selected_pair
.remote
->addr
;
2321 if (nice_socket_send (sock
, addr
, len
, buf
)) {
2333 NICEAPI_EXPORT GSList
*
2334 nice_agent_get_local_candidates (
2339 Component
*component
;
2340 GSList
* ret
= NULL
;
2341 GSList
* item
= NULL
;
2345 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
)) {
2349 for (item
= component
->local_candidates
; item
; item
= item
->next
)
2350 ret
= g_slist_append (ret
, nice_candidate_copy (item
->data
));
2358 NICEAPI_EXPORT GSList
*
2359 nice_agent_get_remote_candidates (
2364 Component
*component
;
2365 GSList
*ret
= NULL
, *item
= NULL
;
2368 if (!agent_find_component (agent
, stream_id
, component_id
, NULL
, &component
))
2373 for (item
= component
->remote_candidates
; item
; item
= item
->next
)
2374 ret
= g_slist_append (ret
, nice_candidate_copy (item
->data
));
2383 nice_agent_restart (
2387 gboolean res
= TRUE
;
2391 /* step: clean up all connectivity checks */
2392 conn_check_free (agent
);
2394 /* step: regenerate tie-breaker value */
2395 priv_generate_tie_breaker (agent
);
2397 for (i
= agent
->streams
; i
&& res
; i
= i
->next
) {
2398 Stream
*stream
= i
->data
;
2400 /* step: reset local credentials for the stream and
2401 * clean up the list of remote candidates */
2402 res
= stream_restart (stream
, agent
->rng
);
2411 nice_agent_dispose (GObject
*object
)
2414 NiceAgent
*agent
= NICE_AGENT (object
);
2416 /* step: free resources for the binding discovery timers */
2417 discovery_free (agent
);
2418 g_assert (agent
->discovery_list
== NULL
);
2419 refresh_free (agent
);
2420 g_assert (agent
->refresh_list
== NULL
);
2422 /* step: free resources for the connectivity check timers */
2423 conn_check_free (agent
);
2425 priv_remove_keepalive_timer (agent
);
2427 for (i
= agent
->local_addresses
; i
; i
= i
->next
)
2429 NiceAddress
*a
= i
->data
;
2431 nice_address_free (a
);
2434 g_slist_free (agent
->local_addresses
);
2435 agent
->local_addresses
= NULL
;
2437 for (i
= agent
->streams
; i
; i
= i
->next
)
2439 Stream
*s
= i
->data
;
2444 g_slist_free (agent
->streams
);
2445 agent
->streams
= NULL
;
2447 g_free (agent
->stun_server_ip
);
2448 agent
->stun_server_ip
= NULL
;
2450 nice_rng_free (agent
->rng
);
2453 priv_free_upnp (agent
);
2455 g_free (agent
->software_attribute
);
2456 agent
->software_attribute
= NULL
;
2458 if (agent
->main_context
!= NULL
)
2459 g_main_context_unref (agent
->main_context
);
2460 agent
->main_context
= NULL
;
2462 if (G_OBJECT_CLASS (nice_agent_parent_class
)->dispose
)
2463 G_OBJECT_CLASS (nice_agent_parent_class
)->dispose (object
);
2468 typedef struct _IOCtx IOCtx
;
2472 GIOChannel
*channel
;
2476 Component
*component
;
2485 Component
*component
,
2487 GIOChannel
*channel
,
2492 ctx
= g_slice_new0 (IOCtx
);
2495 ctx
->stream
= stream
;
2496 ctx
->component
= component
;
2497 ctx
->socket
= socket
;
2498 ctx
->channel
= channel
;
2499 ctx
->source
= source
;
2506 io_ctx_free (IOCtx
*ctx
)
2508 g_io_channel_unref (ctx
->channel
);
2509 g_slice_free (IOCtx
, ctx
);
2513 nice_agent_g_source_cb (
2516 GIOCondition condition
,
2519 /* return value is whether to keep the source */
2522 NiceAgent
*agent
= ctx
->agent
;
2523 Stream
*stream
= ctx
->stream
;
2524 Component
*component
= ctx
->component
;
2525 gchar buf
[MAX_BUFFER_SIZE
];
2530 if (g_source_is_destroyed (g_main_current_source ())) {
2535 /* note: dear compiler, these are for you: */
2538 len
= _nice_agent_recv (agent
, stream
, component
, ctx
->socket
,
2539 MAX_BUFFER_SIZE
, buf
);
2541 if (len
> 0 && component
->tcp
) {
2542 g_object_add_weak_pointer (G_OBJECT (agent
), (gpointer
*)&agent
);
2543 pseudo_tcp_socket_notify_packet (component
->tcp
, buf
, len
);
2545 adjust_tcp_clock (agent
, stream
, component
);
2546 g_object_remove_weak_pointer (G_OBJECT (agent
), (gpointer
*)&agent
);
2548 nice_debug ("Our agent got destroyed in notify_packet!!");
2550 } else if(len
> 0 && agent
->reliable
) {
2551 nice_debug ("Received data on a pseudo tcp FAILED component");
2552 } else if (len
> 0 && component
->g_source_io_cb
) {
2553 gpointer data
= component
->data
;
2554 gint sid
= stream
->id
;
2555 gint cid
= component
->id
;
2556 NiceAgentRecvFunc callback
= component
->g_source_io_cb
;
2557 /* Unlock the agent before calling the callback */
2559 callback (agent
, sid
, cid
, len
, buf
, data
);
2561 } else if (len
< 0) {
2562 GSource
*source
= ctx
->source
;
2564 nice_debug ("Agent %p: _nice_agent_recv returned %d, errno (%d) : %s",
2565 agent
, len
, errno
, g_strerror (errno
));
2566 component
->gsources
= g_slist_remove (component
->gsources
, source
);
2567 g_source_destroy (source
);
2568 g_source_unref (source
);
2569 /* We don't close the socket because it would be way too complicated to
2570 * take care of every path where the socket might still be used.. */
2571 nice_debug ("Agent %p: unable to recv from socket %p. Detaching", agent
,
2584 * Attaches one socket handle to the main loop event context
2588 agent_attach_stream_component_socket (NiceAgent
*agent
,
2590 Component
*component
,
2597 if (!component
->ctx
)
2600 io
= g_io_channel_unix_new (socket
->fileno
);
2601 /* note: without G_IO_ERR the glib mainloop goes into
2602 * busyloop if errors are encountered */
2603 source
= g_io_create_watch (io
, G_IO_IN
| G_IO_ERR
);
2604 ctx
= io_ctx_new (agent
, stream
, component
, socket
, io
, source
);
2605 g_source_set_callback (source
, (GSourceFunc
) nice_agent_g_source_cb
,
2606 ctx
, (GDestroyNotify
) io_ctx_free
);
2607 nice_debug ("Agent %p : Attach source %p (stream %u).", agent
, source
, stream
->id
);
2608 g_source_attach (source
, component
->ctx
);
2609 component
->gsources
= g_slist_append (component
->gsources
, source
);
2614 * Attaches socket handles of 'stream' to the main eventloop
2619 priv_attach_stream_component (NiceAgent
*agent
,
2621 Component
*component
)
2625 for (i
= component
->sockets
; i
; i
= i
->next
)
2626 agent_attach_stream_component_socket (agent
, stream
, component
, i
->data
);
2632 * Detaches socket handles of 'stream' from the main eventloop
2636 static void priv_detach_stream_component (Stream
*stream
, Component
*component
)
2640 for (i
= component
->gsources
; i
; i
= i
->next
) {
2641 GSource
*source
= i
->data
;
2642 nice_debug ("Detach source %p (stream %u).", source
, stream
->id
);
2643 g_source_destroy (source
);
2644 g_source_unref (source
);
2647 g_slist_free (component
->gsources
);
2648 component
->gsources
= NULL
;
2651 NICEAPI_EXPORT gboolean
2652 nice_agent_attach_recv (
2657 NiceAgentRecvFunc func
,
2660 Component
*component
= NULL
;
2661 Stream
*stream
= NULL
;
2662 gboolean ret
= FALSE
;
2666 /* attach candidates */
2668 /* step: check that params specify an existing pair */
2669 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
2670 g_warning ("Could not find component %u in stream %u", component_id
,
2675 if (component
->g_source_io_cb
)
2676 priv_detach_stream_component (stream
, component
);
2681 component
->g_source_io_cb
= func
;
2682 component
->data
= data
;
2683 component
->ctx
= ctx
;
2685 priv_attach_stream_component (agent
, stream
, component
);
2687 /* If we got detached, maybe our readable callback didn't finish reading
2688 * all available data in the pseudotcp, so we need to make sure we free
2689 * our recv window, so the readable callback can be triggered again on the
2690 * next incoming data.
2691 * but only do this if we know we're already readable, otherwise we might
2692 * trigger an error in the initial, pre-connection attach. */
2693 if (component
->tcp
&& component
->tcp_data
&& component
->tcp_readable
)
2694 pseudo_tcp_socket_readable (component
->tcp
, component
->tcp_data
);
2697 component
->g_source_io_cb
= NULL
;
2698 component
->data
= NULL
;
2699 component
->ctx
= NULL
;
2708 NICEAPI_EXPORT gboolean
2709 nice_agent_set_selected_pair (
2713 const gchar
*lfoundation
,
2714 const gchar
*rfoundation
)
2716 Component
*component
;
2719 gboolean ret
= FALSE
;
2723 /* step: check that params specify an existing pair */
2724 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
2728 if (!component_find_pair (component
, agent
, lfoundation
, rfoundation
, &pair
)){
2732 /* step: stop connectivity checks (note: for the whole stream) */
2733 conn_check_prune_stream (agent
, stream
);
2735 if (agent
->reliable
&& component
->tcp
== NULL
) {
2736 nice_debug ("Agent %p: not setting selected pair for s%d:%d because "
2737 "pseudo tcp socket does not exist in reliable mode", agent
,
2738 stream
->id
, component
->id
);
2742 /* step: change component state */
2743 agent_signal_component_state_change (agent
, stream_id
, component_id
, NICE_COMPONENT_STATE_READY
);
2745 /* step: set the selected pair */
2746 component_update_selected_pair (component
, &pair
);
2747 agent_signal_new_selected_pair (agent
, stream_id
, component_id
, lfoundation
, rfoundation
);
2757 GSource
* agent_timeout_add_with_context (NiceAgent
*agent
, guint interval
,
2758 GSourceFunc function
, gpointer data
)
2763 g_return_val_if_fail (function
!= NULL
, 0);
2765 source
= g_timeout_source_new (interval
);
2767 g_source_set_callback (source
, function
, data
, NULL
);
2768 id
= g_source_attach (source
, agent
->main_context
);
2774 NICEAPI_EXPORT gboolean
2775 nice_agent_set_selected_remote_candidate (
2779 NiceCandidate
*candidate
)
2781 Component
*component
;
2783 NiceCandidate
*lcandidate
= NULL
;
2784 gboolean ret
= FALSE
;
2788 /* step: check if the component exists*/
2789 if (!agent_find_component (agent
, stream_id
, component_id
, &stream
, &component
)) {
2793 /* step: stop connectivity checks (note: for the whole stream) */
2794 conn_check_prune_stream (agent
, stream
);
2797 if (agent
->reliable
&& component
->tcp
== NULL
) {
2798 nice_debug ("Agent %p: not setting selected remote candidate s%d:%d because "
2799 "pseudo tcp socket does not exist in reliable mode", agent
,
2800 stream
->id
, component
->id
);
2804 /* step: set the selected pair */
2805 lcandidate
= component_set_selected_remote_candidate (agent
, component
,
2810 /* step: change component state */
2811 agent_signal_component_state_change (agent
, stream_id
, component_id
, NICE_COMPONENT_STATE_READY
);
2813 agent_signal_new_selected_pair (agent
, stream_id
, component_id
,
2814 lcandidate
->foundation
,
2815 candidate
->foundation
);
2825 _priv_set_socket_tos (NiceAgent
*agent
, NiceSocket
*sock
, gint tos
)
2827 if (setsockopt (sock
->fileno
, IPPROTO_IP
,
2828 IP_TOS
, &tos
, sizeof (tos
)) < 0) {
2829 nice_debug ("Agent %p: Could not set socket ToS", agent
,
2830 g_strerror (errno
));
2833 if (setsockopt (sock
->fileno
, IPPROTO_IPV6
,
2834 IPV6_TCLASS
, &tos
, sizeof (tos
)) < 0) {
2835 nice_debug ("Agent %p: Could not set IPV6 socket ToS", agent
,
2836 g_strerror (errno
));
2842 void nice_agent_set_stream_tos (NiceAgent
*agent
,
2843 guint stream_id
, gint tos
)
2850 for (i
= agent
->streams
; i
; i
= i
->next
) {
2851 Stream
*stream
= i
->data
;
2852 if (stream
->id
== stream_id
) {
2854 for (j
= stream
->components
; j
; j
= j
->next
) {
2855 Component
*component
= j
->data
;
2857 for (k
= component
->local_candidates
; k
; k
= k
->next
) {
2858 NiceCandidate
*local_candidate
= k
->data
;
2859 _priv_set_socket_tos (agent
, local_candidate
->sockptr
, tos
);
2868 void nice_agent_set_software (NiceAgent
*agent
, const gchar
*software
)
2872 g_free (agent
->software_attribute
);
2874 agent
->software_attribute
= g_strdup_printf ("%s/%s",
2875 software
, PACKAGE_STRING
);
2877 stun_agent_set_software (&agent
->stun_agent
, agent
->software_attribute
);