2 * This file is part of the Nice GLib ICE library.
4 * (C) 2006-2010, 2013 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.
28 * Philip Withnall, Collabora Ltd.
30 * Alternatively, the contents of this file may be used under the terms of the
31 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
32 * case the provisions of LGPL are applicable instead of those above. If you
33 * wish to allow use of your version of this file only under the terms of the
34 * LGPL and not to allow others to use your version of this file under the
35 * MPL, indicate your decision by deleting the provisions above and replace
36 * them with the notice and other provisions required by the LGPL. If you do
37 * not delete the provisions above, a recipient may use your version of this
38 * file under either the MPL or the LGPL.
45 #define NICEAPI_EXPORT
49 #include <gobject/gvaluecollector.h>
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"
73 #include "interfaces.h"
75 #include "pseudotcp.h"
76 #include "agent-enum-types.h"
78 /* Maximum size of a UDP packet’s payload, as the packet’s length field is 16b
80 #define MAX_BUFFER_SIZE ((1 << 16) - 1) /* 65535 */
82 #define DEFAULT_STUN_PORT 3478
83 #define DEFAULT_UPNP_TIMEOUT 200 /* milliseconds */
84 #define DEFAULT_IDLE_TIMEOUT 5000 /* milliseconds */
86 #define MAX_TCP_MTU 1400 /* Use 1400 because of VPNs and we assume IEE 802.3 */
90 nice_debug_input_message_composition (const NiceInputMessage *messages,
92 static const gchar *_cand_type_to_sdp (NiceCandidateType type);
94 G_DEFINE_TYPE (NiceAgent, nice_agent, G_TYPE_OBJECT);
98 PROP_COMPATIBILITY = 1,
101 PROP_STUN_SERVER_PORT,
102 PROP_CONTROLLING_MODE,
104 PROP_STUN_PACING_TIMER,
105 PROP_MAX_CONNECTIVITY_CHECKS,
117 PROP_KEEPALIVE_CONNCHECK,
119 PROP_STUN_MAX_RETRANSMISSIONS,
120 PROP_STUN_INITIAL_TIMEOUT,
121 PROP_STUN_RELIABLE_TIMEOUT,
122 PROP_NOMINATION_MODE,
124 PROP_SUPPORT_RENOMINATION,
131 SIGNAL_COMPONENT_STATE_CHANGED,
132 SIGNAL_CANDIDATE_GATHERING_DONE,
133 SIGNAL_NEW_SELECTED_PAIR,
134 SIGNAL_NEW_CANDIDATE,
135 SIGNAL_NEW_REMOTE_CANDIDATE,
136 SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED,
137 SIGNAL_RELIABLE_TRANSPORT_WRITABLE,
138 SIGNAL_STREAMS_REMOVED,
139 SIGNAL_NEW_SELECTED_PAIR_FULL,
140 SIGNAL_NEW_CANDIDATE_FULL,
141 SIGNAL_NEW_REMOTE_CANDIDATE_FULL,
146 static guint signals[N_SIGNALS];
148 static void priv_stop_upnp (NiceAgent *agent);
150 static void pseudo_tcp_socket_opened (PseudoTcpSocket *sock, gpointer user_data);
151 static void pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data);
152 static void pseudo_tcp_socket_writable (PseudoTcpSocket *sock, gpointer user_data);
153 static void pseudo_tcp_socket_closed (PseudoTcpSocket *sock, guint32 err,
155 static PseudoTcpWriteResult pseudo_tcp_socket_write_packet (PseudoTcpSocket *sock,
156 const gchar *buffer, guint32 len, gpointer user_data);
157 static void adjust_tcp_clock (NiceAgent *agent, NiceStream *stream, NiceComponent *component);
159 static void nice_agent_dispose (GObject *object);
160 static void nice_agent_get_property (GObject *object,
161 guint property_id, GValue *value, GParamSpec *pspec);
162 static void nice_agent_set_property (GObject *object,
163 guint property_id, const GValue *value, GParamSpec *pspec);
165 void agent_lock (NiceAgent *agent)
167 g_mutex_lock (&agent->agent_mutex);
170 void agent_unlock (NiceAgent *agent)
172 g_mutex_unlock (&agent->agent_mutex);
175 static GType _nice_agent_stream_ids_get_type (void);
177 G_DEFINE_POINTER_TYPE (_NiceAgentStreamIds, _nice_agent_stream_ids);
179 #define NICE_TYPE_AGENT_STREAM_IDS _nice_agent_stream_ids_get_type ()
189 free_queued_signal (QueuedSignal *sig)
193 g_value_unset (&sig->params[0]);
195 for (i = 0; i < sig->query.n_params; i++) {
196 if (G_VALUE_HOLDS(&sig->params[i + 1], NICE_TYPE_AGENT_STREAM_IDS))
197 g_free (g_value_get_pointer (&sig->params[i + 1]));
198 g_value_unset (&sig->params[i + 1]);
201 g_slice_free1 (sizeof(GValue) * (sig->query.n_params + 1), sig->params);
202 g_slice_free (QueuedSignal, sig);
206 agent_unlock_and_emit (NiceAgent *agent)
208 GQueue queue = G_QUEUE_INIT;
211 queue = agent->pending_signals;
212 g_queue_init (&agent->pending_signals);
214 agent_unlock (agent);
216 while ((sig = g_queue_pop_head (&queue))) {
217 g_signal_emitv (sig->params, sig->signal_id, 0, NULL);
219 free_queued_signal (sig);
224 agent_queue_signal (NiceAgent *agent, guint signal_id, ...)
231 sig = g_slice_new (QueuedSignal);
232 g_signal_query (signal_id, &sig->query);
234 sig->signal_id = signal_id;
235 sig->params = g_slice_alloc0 (sizeof(GValue) * (sig->query.n_params + 1));
237 g_value_init (&sig->params[0], G_TYPE_OBJECT);
238 g_value_set_object (&sig->params[0], agent);
240 va_start (var_args, signal_id);
241 for (i = 0; i < sig->query.n_params; i++) {
242 G_VALUE_COLLECT_INIT (&sig->params[i + 1], sig->query.param_types[i],
243 var_args, 0, &error);
250 free_queued_signal (sig);
251 g_critical ("Error collecting values for signal: %s", error);
256 g_queue_push_tail (&agent->pending_signals, sig);
260 StunUsageIceCompatibility
261 agent_to_ice_compatibility (NiceAgent *agent)
263 return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
264 STUN_USAGE_ICE_COMPATIBILITY_GOOGLE :
265 agent->compatibility == NICE_COMPATIBILITY_MSN ?
266 STUN_USAGE_ICE_COMPATIBILITY_MSN :
267 agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
268 STUN_USAGE_ICE_COMPATIBILITY_MSICE2 :
269 agent->compatibility == NICE_COMPATIBILITY_OC2007 ?
270 STUN_USAGE_ICE_COMPATIBILITY_MSN :
271 agent->compatibility == NICE_COMPATIBILITY_OC2007R2 ?
272 STUN_USAGE_ICE_COMPATIBILITY_MSICE2 :
273 STUN_USAGE_ICE_COMPATIBILITY_RFC5245;
277 StunUsageTurnCompatibility
278 agent_to_turn_compatibility (NiceAgent *agent)
280 return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
281 STUN_USAGE_TURN_COMPATIBILITY_GOOGLE :
282 agent->compatibility == NICE_COMPATIBILITY_MSN ?
283 STUN_USAGE_TURN_COMPATIBILITY_MSN :
284 agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
285 STUN_USAGE_TURN_COMPATIBILITY_MSN :
286 agent->compatibility == NICE_COMPATIBILITY_OC2007 ?
287 STUN_USAGE_TURN_COMPATIBILITY_OC2007 :
288 agent->compatibility == NICE_COMPATIBILITY_OC2007R2 ?
289 STUN_USAGE_TURN_COMPATIBILITY_OC2007 :
290 STUN_USAGE_TURN_COMPATIBILITY_RFC5766;
293 NiceTurnSocketCompatibility
294 agent_to_turn_socket_compatibility (NiceAgent *agent)
296 return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
297 NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE :
298 agent->compatibility == NICE_COMPATIBILITY_MSN ?
299 NICE_TURN_SOCKET_COMPATIBILITY_MSN :
300 agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
301 NICE_TURN_SOCKET_COMPATIBILITY_MSN :
302 agent->compatibility == NICE_COMPATIBILITY_OC2007 ?
303 NICE_TURN_SOCKET_COMPATIBILITY_OC2007 :
304 agent->compatibility == NICE_COMPATIBILITY_OC2007R2 ?
305 NICE_TURN_SOCKET_COMPATIBILITY_OC2007 :
306 NICE_TURN_SOCKET_COMPATIBILITY_RFC5766;
309 NiceStream *agent_find_stream (NiceAgent *agent, guint stream_id)
313 for (i = agent->streams; i; i = i->next)
315 NiceStream *s = i->data;
317 if (s->id == stream_id)
326 agent_find_component (
331 NiceComponent **component)
336 s = agent_find_stream (agent, stream_id);
341 c = nice_stream_find_component_by_id (s, component_id);
356 nice_agent_class_init (NiceAgentClass *klass)
358 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
360 gobject_class->get_property = nice_agent_get_property;
361 gobject_class->set_property = nice_agent_set_property;
362 gobject_class->dispose = nice_agent_dispose;
364 /* install properties */
366 * NiceAgent:main-context:
368 * A GLib main context is needed for all timeouts used by libnice.
369 * This is a property being set by the nice_agent_new() call.
371 g_object_class_install_property (gobject_class, PROP_MAIN_CONTEXT,
372 g_param_spec_pointer (
374 "The GMainContext to use for timeouts",
375 "The GMainContext to use for timeouts",
376 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
379 * NiceAgent:compatibility:
381 * The Nice agent can work in various compatibility modes depending on
382 * what the application/peer needs.
383 * <para> See also: #NiceCompatibility</para>
385 g_object_class_install_property (gobject_class, PROP_COMPATIBILITY,
388 "ICE specification compatibility",
389 "The compatibility mode for the agent",
390 NICE_COMPATIBILITY_RFC5245, NICE_COMPATIBILITY_LAST,
391 NICE_COMPATIBILITY_RFC5245,
392 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
394 g_object_class_install_property (gobject_class, PROP_STUN_SERVER,
395 g_param_spec_string (
397 "STUN server IP address",
398 "The IP address (not the hostname) of the STUN server to use",
402 g_object_class_install_property (gobject_class, PROP_STUN_SERVER_PORT,
406 "Port of the STUN server used to gather server-reflexive candidates",
408 1, /* not a construct property, ignored */
412 * NiceAgent:controlling-mode:
414 * Whether the agent has the controlling role. This property should
415 * be modified before gathering candidates, any modification occuring
416 * later will be hold until ICE is restarted.
418 g_object_class_install_property (gobject_class, PROP_CONTROLLING_MODE,
419 g_param_spec_boolean (
421 "ICE controlling mode",
422 "Whether the agent is in controlling mode",
423 FALSE, /* not a construct property, ignored */
426 g_object_class_install_property (gobject_class, PROP_FULL_MODE,
427 g_param_spec_boolean (
430 "Whether agent runs in ICE full mode",
431 TRUE, /* use full mode by default */
432 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
434 g_object_class_install_property (gobject_class, PROP_STUN_PACING_TIMER,
438 "Timer 'Ta' (msecs) used in the IETF ICE specification for pacing "
439 "candidate gathering and sending of connectivity checks",
441 NICE_AGENT_TIMER_TA_DEFAULT,
442 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
444 /* note: according to spec recommendation in sect 5.7.3 (ID-19) */
445 g_object_class_install_property (gobject_class, PROP_MAX_CONNECTIVITY_CHECKS,
447 "max-connectivity-checks",
448 "Maximum number of connectivity checks",
449 "Upper limit for the total number of connectivity checks performed",
451 0, /* default set in init */
455 * NiceAgent:nomination-mode:
457 * The nomination mode used in the ICE specification for describing
458 * the selection of valid pairs to be used upstream.
459 * <para> See also: #NiceNominationMode </para>
463 g_object_class_install_property (gobject_class, PROP_NOMINATION_MODE,
466 "ICE nomination mode",
467 "Nomination mode used in the ICE specification for describing "
468 "the selection of valid pairs to be used upstream",
469 NICE_TYPE_NOMINATION_MODE, NICE_NOMINATION_MODE_AGGRESSIVE,
470 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
473 * NiceAgent:support-renomination:
475 * Support RENOMINATION STUN attribute proposed here:
476 * https://tools.ietf.org/html/draft-thatcher-ice-renomination-00 As
477 * soon as RENOMINATION attribute is received from remote
478 * candidate's address, corresponding candidates pair gets
479 * selected. This is specific to Google Chrome/libWebRTC.
481 g_object_class_install_property (gobject_class, PROP_SUPPORT_RENOMINATION,
482 g_param_spec_boolean (
483 "support-renomination",
484 "Support RENOMINATION STUN attribute",
485 "As soon as RENOMINATION attribute is received from remote candidate's address, "
486 "corresponding candidates pair gets selected.",
491 * NiceAgent:idle-timeout
493 * A final timeout in msec, launched when the agent becomes idle,
494 * before stopping its activity.
496 * This timer will delay the decision to set a component as failed.
497 * This delay is added to reduce the chance to see the agent receiving
498 * new stun activity just after the conncheck list has been declared
499 * failed (some valid pairs, no nominated pair, and no in-progress
500 * pairs), reactiviting conncheck activity, and causing a (valid)
501 * state transitions like that: connecting -> failed -> connecting ->
502 * connected -> ready. Such transitions are not buggy per-se, but may
503 * break the test-suite, that counts precisely the number of time each
504 * state has been set, and doesnt expect these transcient failed
507 * This timer is also useful when the agent is in controlled mode and
508 * the other controlling peer takes some time to elect its nominated
509 * pair (this may be the case for SfB peers).
511 * This timer is *NOT* part if the RFC5245, as this situation is not
512 * covered in sect 8.1.2 "Updating States", but deals with a real
513 * use-case, where a controlled agent can not wait forever for the
514 * other peer to make a nomination decision.
516 * Also note that the value of this timeout will not delay the
517 * emission of 'connected' and 'ready' agent signals, and will not
518 * slow down the behaviour of the agent when the peer agent works
519 * in a timely manner.
524 g_object_class_install_property (gobject_class, PROP_IDLE_TIMEOUT,
527 "Timeout before stopping the agent when being idle",
528 "A final timeout in msecs, launched when the agent becomes idle, "
529 "with no in-progress pairs to wait for, before stopping its activity, "
530 "and declaring a component as failed in needed.",
532 DEFAULT_IDLE_TIMEOUT,
533 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
536 * NiceAgent:proxy-ip:
538 * The proxy server IP used to bypass a proxy firewall
542 g_object_class_install_property (gobject_class, PROP_PROXY_IP,
543 g_param_spec_string (
546 "The proxy server IP used to bypass a proxy firewall",
551 * NiceAgent:proxy-port:
553 * The proxy server port used to bypass a proxy firewall
557 g_object_class_install_property (gobject_class, PROP_PROXY_PORT,
561 "The Proxy server port used to bypass a proxy firewall",
567 * NiceAgent:proxy-type:
569 * The type of proxy set in the proxy-ip property
573 g_object_class_install_property (gobject_class, PROP_PROXY_TYPE,
576 "Type of proxy to use",
577 "The type of proxy set in the proxy-ip property",
578 NICE_PROXY_TYPE_NONE, NICE_PROXY_TYPE_LAST,
579 NICE_PROXY_TYPE_NONE,
583 * NiceAgent:proxy-username:
585 * The username used to authenticate with the proxy
589 g_object_class_install_property (gobject_class, PROP_PROXY_USERNAME,
590 g_param_spec_string (
592 "Proxy server username",
593 "The username used to authenticate with the proxy",
598 * NiceAgent:proxy-password:
600 * The password used to authenticate with the proxy
604 g_object_class_install_property (gobject_class, PROP_PROXY_PASSWORD,
605 g_param_spec_string (
607 "Proxy server password",
608 "The password used to authenticate with the proxy",
615 * Whether the agent should use UPnP to open a port in the router and
616 * get the external IP
620 g_object_class_install_property (gobject_class, PROP_UPNP,
621 g_param_spec_boolean (
625 "Whether the agent should use UPnP to open a port in the router and "
626 "get the external IP",
628 "Use UPnP (disabled in build)",
629 "Does nothing because libnice was not built with UPnP support",
631 TRUE, /* enable UPnP by default */
632 G_PARAM_READWRITE| G_PARAM_CONSTRUCT));
635 * NiceAgent:upnp-timeout:
637 * The maximum amount of time (in milliseconds) to wait for UPnP discovery to
638 * finish before signaling the #NiceAgent::candidate-gathering-done signal
642 g_object_class_install_property (gobject_class, PROP_UPNP_TIMEOUT,
646 "Timeout for UPnP discovery",
647 "The maximum amount of time to wait for UPnP discovery to finish before "
648 "signaling the candidate-gathering-done signal",
650 "Timeout for UPnP discovery (disabled in build)",
651 "Does nothing because libnice was not built with UPnP support",
654 DEFAULT_UPNP_TIMEOUT,
655 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
658 * NiceAgent:reliable:
660 * Whether the agent is providing a reliable transport of messages (through
661 * ICE-TCP or PseudoTCP over ICE-UDP)
665 g_object_class_install_property (gobject_class, PROP_RELIABLE,
666 g_param_spec_boolean (
669 "Whether the agent provides a reliable transport of messages",
671 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
676 * Whether the agent should use ICE-UDP when gathering candidates.
677 * If the option is disabled, no UDP candidates will be generated. If the
678 * agent is in reliable mode, then pseudotcp will not be used since pseudotcp
679 * works on top of UDP candidates.
681 * This option should be set before gathering candidates and should not be
682 * modified afterwards.
684 * The #NiceAgent:ice-udp property can be set at the same time as the
685 * #NiceAgent:ice-tcp property, but both cannot be unset at the same time.
686 * If #NiceAgent:ice-tcp is set to %FALSE, then this property cannot be set
691 g_object_class_install_property (gobject_class, PROP_ICE_UDP,
692 g_param_spec_boolean (
695 "Use ICE-UDP specification to generate UDP candidates",
696 TRUE, /* use ice-udp by default */
702 * Whether the agent should use ICE-TCP when gathering candidates.
703 * If the option is disabled, no TCP candidates will be generated. If the
704 * agent is in reliable mode, then pseudotcp will need to be used over UDP
707 * This option should be set before gathering candidates and should not be
708 * modified afterwards.
710 * The #NiceAgent:ice-tcp property can be set at the same time as the
711 * #NiceAgent:ice-udp property, but both cannot be unset at the same time.
712 * If #NiceAgent:ice-udp is set to %FALSE, then this property cannot be set
716 ICE-TCP is only supported for %NICE_COMPATIBILITY_RFC5245,
717 %NICE_COMPATIBILITY_OC2007 and %NICE_COMPATIBILITY_OC2007R2 compatibility
724 g_object_class_install_property (gobject_class, PROP_ICE_TCP,
725 g_param_spec_boolean (
728 "Use ICE-TCP specification to generate TCP candidates",
729 TRUE, /* use ice-tcp by default */
733 * NiceAgent:bytestream-tcp:
735 * This property defines whether receive/send over a TCP or pseudo-TCP, in
736 * reliable mode, are considered as packetized or as bytestream.
737 * In unreliable mode, every send/recv is considered as packetized, and
738 * this property is ignored and cannot be set.
740 * In reliable mode, this property will always return %TRUE in the
741 * %NICE_COMPATIBILITY_GOOGLE compatibility mode.
743 * If the property is %TRUE, the stream is considered in bytestream mode
744 * and data can be read with any receive size. If the property is %FALSE, then
745 * the stream is considred packetized and each receive will return one packet
746 * of the same size as what was sent from the peer. If in packetized mode,
747 * then doing a receive with a size smaller than the packet, will cause the
748 * remaining bytes in the packet to be dropped, breaking the reliability
751 * This property is currently read-only, and will become read/write once
752 * bytestream mode will be supported.
757 g_object_class_install_property (gobject_class, PROP_BYTESTREAM_TCP,
758 g_param_spec_boolean (
761 "Use bytestream mode for reliable TCP and Pseudo-TCP connections",
766 * NiceAgent:keepalive-conncheck:
768 * Use binding requests as keepalives instead of binding
769 * indications. This means that the keepalives may time out which
770 * will change the component state to %NICE_COMPONENT_STATE_FAILED.
772 * Enabing this is a slight violation of RFC 5245 section 10 which
773 * recommends using Binding Indications for keepalives.
775 * This is always enabled if the compatibility mode is
776 * %NICE_COMPATIBILITY_GOOGLE.
780 g_object_class_install_property (gobject_class, PROP_KEEPALIVE_CONNCHECK,
781 g_param_spec_boolean (
782 "keepalive-conncheck",
783 "Use conncheck as keepalives",
784 "Use binding requests which require a reply as keepalives instead of "
785 "binding indications which don't.",
790 * NiceAgent:force-relay
792 * Force all traffic to go through a relay for added privacy, this
793 * allows hiding the local IP address. When this is enabled, so
794 * local candidates are available before relay servers have been set
795 * with nice_agent_set_relay_info().
799 g_object_class_install_property (gobject_class, PROP_FORCE_RELAY,
800 g_param_spec_boolean (
803 "Force all traffic to go through a relay for added privacy.",
808 * NiceAgent:stun-max-retransmissions
810 * The maximum number of retransmissions of the STUN binding requests
811 * used in the gathering stage, to find our local candidates, and used
812 * in the connection check stage, to test the validity of each
813 * constructed pair. This property is described as 'Rc' in the RFC
814 * 5389, with a default value of 7. The timeout of each STUN request
815 * is doubled for each retransmission, so the choice of this value has
816 * a direct impact on the time needed to move from the CONNECTED state
817 * to the READY state, and on the time needed to complete the GATHERING
823 g_object_class_install_property (gobject_class, PROP_STUN_MAX_RETRANSMISSIONS,
825 "stun-max-retransmissions",
826 "STUN Max Retransmissions",
827 "Maximum number of STUN binding requests retransmissions "
828 "described as 'Rc' in the STUN specification.",
830 STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS,
831 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
834 * NiceAgent:stun-initial-timeout
836 * The initial timeout (msecs) of the STUN binding requests
837 * used in the gathering stage, to find our local candidates.
838 * This property is described as 'RTO' in the RFC 5389 and RFC 5245.
839 * This timeout is doubled for each retransmission, until
840 * #NiceAgent:stun-max-retransmissions have been done,
841 * with an exception for the last restransmission, where the timeout is
842 * divided by two instead (RFC 5389 indicates that a customisable
843 * multiplier 'Rm' to 'RTO' should be used).
848 g_object_class_install_property (gobject_class, PROP_STUN_INITIAL_TIMEOUT,
850 "stun-initial-timeout",
851 "STUN Initial Timeout",
852 "STUN timeout in msecs of the initial binding requests used in the "
853 "gathering state, described as 'RTO' in the ICE specification.",
855 STUN_TIMER_DEFAULT_TIMEOUT,
856 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
859 * NiceAgent:stun-reliable-timeout
861 * The initial timeout of the STUN binding requests used
862 * for a reliable timer.
867 g_object_class_install_property (gobject_class, PROP_STUN_RELIABLE_TIMEOUT,
869 "stun-reliable-timeout",
870 "STUN Reliable Timeout",
871 "STUN timeout in msecs of the initial binding requests used for "
874 STUN_TIMER_DEFAULT_RELIABLE_TIMEOUT,
875 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
878 * NiceAgent:ice-trickle
880 * Whether to perform Trickle ICE as per draft-ietf-ice-trickle-ice-21.
881 * When %TRUE, the agent will postpone changing a component state to
882 * %NICE_COMPONENT_STATE_FAILED until nice_agent_peer_candidate_gathering_done()
883 * has been called with the ID of the component's stream.
887 g_object_class_install_property (gobject_class, PROP_ICE_TRICKLE,
888 g_param_spec_boolean (
891 "Whether to perform Trickle ICE as per draft-ietf-ice-trickle-ice-21.",
895 /* install signals */
898 * NiceAgent::component-state-changed
899 * @agent: The #NiceAgent object
900 * @stream_id: The ID of the stream
901 * @component_id: The ID of the component
902 * @state: The new #NiceComponentState of the component
904 * This signal is fired whenever a component’s state changes. There are many
905 * valid state transitions.
907 * ![State transition diagram](states.png)
909 signals[SIGNAL_COMPONENT_STATE_CHANGED] =
911 "component-state-changed",
912 G_OBJECT_CLASS_TYPE (klass),
920 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
924 * NiceAgent::candidate-gathering-done:
925 * @agent: The #NiceAgent object
926 * @stream_id: The ID of the stream
928 * This signal is fired whenever a stream has finished gathering its
929 * candidates after a call to nice_agent_gather_candidates()
931 signals[SIGNAL_CANDIDATE_GATHERING_DONE] =
933 "candidate-gathering-done",
934 G_OBJECT_CLASS_TYPE (klass),
942 G_TYPE_UINT, G_TYPE_INVALID);
945 * NiceAgent::new-selected-pair
946 * @agent: The #NiceAgent object
947 * @stream_id: The ID of the stream
948 * @component_id: The ID of the component
949 * @lfoundation: The local foundation of the selected candidate pair
950 * @rfoundation: The remote foundation of the selected candidate pair
952 * This signal is fired once a candidate pair is selected for data
953 * transfer for a stream's component This is emitted along with
954 * #NiceAgent::new-selected-pair-full which has the whole candidate,
955 * the Foundation of a Candidate is not a unique identifier.
957 * See also: #NiceAgent::new-selected-pair-full
958 * Deprecated: 0.1.8: Use #NiceAgent::new-selected-pair-full
960 signals[SIGNAL_NEW_SELECTED_PAIR] =
963 G_OBJECT_CLASS_TYPE (klass),
971 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING,
975 * NiceAgent::new-candidate
976 * @agent: The #NiceAgent object
977 * @stream_id: The ID of the stream
978 * @component_id: The ID of the component
979 * @foundation: The foundation of the new candidate
981 * This signal is fired when the agent discovers a new local candidate.
982 * When this signal is emitted, a matching #NiceAgent::new-candidate-full is
983 * also emitted with the candidate.
985 * See also: #NiceAgent::candidate-gathering-done,
986 * #NiceAgent::new-candidate-full
987 * Deprecated: 0.1.8: Use #NiceAgent::new-candidate-full
989 signals[SIGNAL_NEW_CANDIDATE] =
992 G_OBJECT_CLASS_TYPE (klass),
1000 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
1004 * NiceAgent::new-remote-candidate
1005 * @agent: The #NiceAgent object
1006 * @stream_id: The ID of the stream
1007 * @component_id: The ID of the component
1008 * @foundation: The foundation of the new candidate
1010 * This signal is fired when the agent discovers a new remote
1011 * candidate. This can happen with peer reflexive candidates. When
1012 * this signal is emitted, a matching
1013 * #NiceAgent::new-remote-candidate-full is also emitted with the
1016 * See also: #NiceAgent::new-remote-candidate-full
1017 * Deprecated: 0.1.8: Use #NiceAgent::new-remote-candidate-full
1019 signals[SIGNAL_NEW_REMOTE_CANDIDATE] =
1021 "new-remote-candidate",
1022 G_OBJECT_CLASS_TYPE (klass),
1030 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
1034 * NiceAgent::initial-binding-request-received
1035 * @agent: The #NiceAgent object
1036 * @stream_id: The ID of the stream
1038 * This signal is fired when we received our first binding request from
1041 signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED] =
1043 "initial-binding-request-received",
1044 G_OBJECT_CLASS_TYPE (klass),
1056 * NiceAgent::reliable-transport-writable
1057 * @agent: The #NiceAgent object
1058 * @stream_id: The ID of the stream
1059 * @component_id: The ID of the component
1061 * This signal is fired on the reliable #NiceAgent when the underlying reliable
1062 * transport becomes writable.
1063 * This signal is only emitted when the nice_agent_send() function returns less
1064 * bytes than requested to send (or -1) and once when the connection
1069 signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE] =
1071 "reliable-transport-writable",
1072 G_OBJECT_CLASS_TYPE (klass),
1080 G_TYPE_UINT, G_TYPE_UINT,
1084 * NiceAgent::streams-removed
1085 * @agent: The #NiceAgent object
1086 * @stream_ids: (array zero-terminated=1) (element-type uint): An array of
1087 * unsigned integer stream IDs, ending with a 0 ID
1089 * This signal is fired whenever one or more streams are removed from the
1094 signals[SIGNAL_STREAMS_REMOVED] =
1097 G_OBJECT_CLASS_TYPE (klass),
1102 g_cclosure_marshal_VOID__POINTER,
1105 NICE_TYPE_AGENT_STREAM_IDS,
1110 * NiceAgent::new-selected-pair-full
1111 * @agent: The #NiceAgent object
1112 * @stream_id: The ID of the stream
1113 * @component_id: The ID of the component
1114 * @lcandidate: The local #NiceCandidate of the selected candidate pair
1115 * @rcandidate: The remote #NiceCandidate of the selected candidate pair
1117 * This signal is fired once a candidate pair is selected for data
1118 * transfer for a stream's component. This is emitted along with
1119 * #NiceAgent::new-selected-pair.
1121 * See also: #NiceAgent::new-selected-pair
1124 signals[SIGNAL_NEW_SELECTED_PAIR_FULL] =
1126 "new-selected-pair-full",
1127 G_OBJECT_CLASS_TYPE (klass),
1134 4, G_TYPE_UINT, G_TYPE_UINT, NICE_TYPE_CANDIDATE, NICE_TYPE_CANDIDATE,
1138 * NiceAgent::new-candidate-full
1139 * @agent: The #NiceAgent object
1140 * @candidate: The new #NiceCandidate
1142 * This signal is fired when the agent discovers a new local candidate.
1143 * When this signal is emitted, a matching #NiceAgent::new-candidate is
1144 * also emitted with the candidate's foundation.
1146 * See also: #NiceAgent::candidate-gathering-done,
1147 * #NiceAgent::new-candidate
1150 signals[SIGNAL_NEW_CANDIDATE_FULL] =
1152 "new-candidate-full",
1153 G_OBJECT_CLASS_TYPE (klass),
1161 NICE_TYPE_CANDIDATE,
1165 * NiceAgent::new-remote-candidate-full
1166 * @agent: The #NiceAgent object
1167 * @candidate: The new #NiceCandidate
1169 * This signal is fired when the agent discovers a new remote candidate.
1170 * This can happen with peer reflexive candidates.
1171 * When this signal is emitted, a matching #NiceAgent::new-remote-candidate is
1172 * also emitted with the candidate's foundation.
1174 * See also: #NiceAgent::new-remote-candidate
1177 signals[SIGNAL_NEW_REMOTE_CANDIDATE_FULL] =
1179 "new-remote-candidate-full",
1180 G_OBJECT_CLASS_TYPE (klass),
1188 NICE_TYPE_CANDIDATE,
1191 /* Init debug options depending on env variables */
1195 static void priv_generate_tie_breaker (NiceAgent *agent)
1197 nice_rng_generate_bytes (agent->rng, 8, (gchar*)&agent->tie_breaker);
1201 priv_update_controlling_mode (NiceAgent *agent, gboolean value)
1203 gboolean update_controlling_mode;
1206 agent->saved_controlling_mode = value;
1207 /* It is safe to update the agent controlling mode when all
1208 * components are still in state disconnected. When we leave
1209 * this state, the role must stay under the control of the
1210 * conncheck algorithm exclusively, until the conncheck is
1211 * eventually restarted. See RFC5245, sect 5.2. Determining Role
1213 if (agent->controlling_mode != agent->saved_controlling_mode) {
1214 update_controlling_mode = TRUE;
1215 for (i = agent->streams;
1216 i && update_controlling_mode; i = i->next) {
1217 NiceStream *stream = i->data;
1218 for (j = stream->components;
1219 j && update_controlling_mode; j = j->next) {
1220 NiceComponent *component = j->data;
1221 if (component->state > NICE_COMPONENT_STATE_DISCONNECTED)
1222 update_controlling_mode = FALSE;
1225 if (update_controlling_mode) {
1226 agent->controlling_mode = agent->saved_controlling_mode;
1227 nice_debug ("Agent %p : Property set, changing role to \"%s\".",
1228 agent, agent->controlling_mode ? "controlling" : "controlled");
1230 nice_debug ("Agent %p : Property set, role switch requested "
1231 "but conncheck already started.", agent);
1232 nice_debug ("Agent %p : Property set, staying with role \"%s\" "
1233 "until restart.", agent,
1234 agent->controlling_mode ? "controlling" : "controlled");
1237 nice_debug ("Agent %p : Property set, role is already \"%s\".", agent,
1238 agent->controlling_mode ? "controlling" : "controlled");
1242 nice_agent_init (NiceAgent *agent)
1244 agent->next_candidate_id = 1;
1245 agent->next_stream_id = 1;
1247 /* set defaults; not construct params, so set here */
1248 agent->stun_server_port = DEFAULT_STUN_PORT;
1249 agent->controlling_mode = TRUE;
1250 agent->saved_controlling_mode = TRUE;
1251 agent->max_conn_checks = NICE_AGENT_MAX_CONNECTIVITY_CHECKS_DEFAULT;
1252 agent->nomination_mode = NICE_NOMINATION_MODE_AGGRESSIVE;
1253 agent->support_renomination = FALSE;
1254 agent->idle_timeout = DEFAULT_IDLE_TIMEOUT;
1256 agent->discovery_list = NULL;
1257 agent->discovery_unsched_items = 0;
1258 agent->discovery_timer_source = NULL;
1259 agent->conncheck_timer_source = NULL;
1260 agent->keepalive_timer_source = NULL;
1261 agent->refresh_list = NULL;
1262 agent->media_after_tick = FALSE;
1263 agent->software_attribute = NULL;
1265 agent->compatibility = NICE_COMPATIBILITY_RFC5245;
1266 agent->reliable = FALSE;
1267 agent->use_ice_udp = TRUE;
1268 agent->use_ice_tcp = TRUE;
1270 agent->rng = nice_rng_new ();
1271 priv_generate_tie_breaker (agent);
1273 g_queue_init (&agent->pending_signals);
1275 g_mutex_init (&agent->agent_mutex);
1279 NICEAPI_EXPORT NiceAgent *
1280 nice_agent_new (GMainContext *ctx, NiceCompatibility compat)
1282 NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
1283 "compatibility", compat,
1284 "main-context", ctx,
1292 NICEAPI_EXPORT NiceAgent *
1293 nice_agent_new_reliable (GMainContext *ctx, NiceCompatibility compat)
1295 NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
1296 "compatibility", compat,
1297 "main-context", ctx,
1305 NICEAPI_EXPORT NiceAgent *
1306 nice_agent_new_full (GMainContext *ctx,
1307 NiceCompatibility compat,
1308 NiceAgentOption flags)
1310 NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
1311 "compatibility", compat,
1312 "main-context", ctx,
1313 "reliable", (flags & NICE_AGENT_OPTION_RELIABLE) ? TRUE : FALSE,
1314 "nomination-mode", (flags & NICE_AGENT_OPTION_REGULAR_NOMINATION) ?
1315 NICE_NOMINATION_MODE_REGULAR : NICE_NOMINATION_MODE_AGGRESSIVE,
1316 "full-mode", (flags & NICE_AGENT_OPTION_LITE_MODE) ? FALSE : TRUE,
1317 "ice-trickle", (flags & NICE_AGENT_OPTION_ICE_TRICKLE) ? TRUE : FALSE,
1318 "support-renomination", (flags & NICE_AGENT_OPTION_SUPPORT_RENOMINATION) ? TRUE : FALSE,
1326 nice_agent_get_property (
1332 NiceAgent *agent = NICE_AGENT (object);
1336 switch (property_id)
1338 case PROP_MAIN_CONTEXT:
1339 g_value_set_pointer (value, agent->main_context);
1342 case PROP_COMPATIBILITY:
1343 g_value_set_uint (value, agent->compatibility);
1346 case PROP_STUN_SERVER:
1347 g_value_set_string (value, agent->stun_server_ip);
1350 case PROP_STUN_SERVER_PORT:
1351 g_value_set_uint (value, agent->stun_server_port);
1354 case PROP_CONTROLLING_MODE:
1355 g_value_set_boolean (value, agent->saved_controlling_mode);
1358 case PROP_FULL_MODE:
1359 g_value_set_boolean (value, agent->full_mode);
1362 case PROP_STUN_PACING_TIMER:
1363 g_value_set_uint (value, agent->timer_ta);
1366 case PROP_MAX_CONNECTIVITY_CHECKS:
1367 g_value_set_uint (value, agent->max_conn_checks);
1368 /* XXX: should we prune the list of already existing checks? */
1371 case PROP_NOMINATION_MODE:
1372 g_value_set_enum (value, agent->nomination_mode);
1375 case PROP_SUPPORT_RENOMINATION:
1376 g_value_set_boolean (value, agent->support_renomination);
1379 case PROP_IDLE_TIMEOUT:
1380 g_value_set_uint (value, agent->idle_timeout);
1384 g_value_set_string (value, agent->proxy_ip);
1387 case PROP_PROXY_PORT:
1388 g_value_set_uint (value, agent->proxy_port);
1391 case PROP_PROXY_TYPE:
1392 g_value_set_uint (value, agent->proxy_type);
1395 case PROP_PROXY_USERNAME:
1396 g_value_set_string (value, agent->proxy_username);
1399 case PROP_PROXY_PASSWORD:
1400 g_value_set_string (value, agent->proxy_password);
1405 g_value_set_boolean (value, agent->upnp_enabled);
1407 g_value_set_boolean (value, FALSE);
1411 case PROP_UPNP_TIMEOUT:
1413 g_value_set_uint (value, agent->upnp_timeout);
1415 g_value_set_uint (value, DEFAULT_UPNP_TIMEOUT);
1420 g_value_set_boolean (value, agent->reliable);
1424 g_value_set_boolean (value, agent->use_ice_udp);
1428 g_value_set_boolean (value, agent->use_ice_tcp);
1431 case PROP_BYTESTREAM_TCP:
1432 if (agent->reliable) {
1433 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE)
1434 g_value_set_boolean (value, TRUE);
1436 g_value_set_boolean (value, FALSE);
1438 g_value_set_boolean (value, FALSE);
1442 case PROP_KEEPALIVE_CONNCHECK:
1443 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE)
1444 g_value_set_boolean (value, TRUE);
1446 g_value_set_boolean (value, agent->keepalive_conncheck);
1449 case PROP_FORCE_RELAY:
1450 g_value_set_boolean (value, agent->force_relay);
1453 case PROP_STUN_MAX_RETRANSMISSIONS:
1454 g_value_set_uint (value, agent->stun_max_retransmissions);
1457 case PROP_STUN_INITIAL_TIMEOUT:
1458 g_value_set_uint (value, agent->stun_initial_timeout);
1461 case PROP_STUN_RELIABLE_TIMEOUT:
1462 g_value_set_uint (value, agent->stun_reliable_timeout);
1465 case PROP_ICE_TRICKLE:
1466 g_value_set_boolean (value, agent->use_ice_trickle);
1470 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1473 agent_unlock_and_emit(agent);
1477 nice_agent_init_stun_agent (NiceAgent *agent, StunAgent *stun_agent)
1479 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
1480 stun_agent_init (stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1481 STUN_COMPATIBILITY_RFC3489,
1482 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
1483 STUN_AGENT_USAGE_IGNORE_CREDENTIALS);
1484 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN) {
1485 stun_agent_init (stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1486 STUN_COMPATIBILITY_RFC3489,
1487 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
1488 STUN_AGENT_USAGE_FORCE_VALIDATER);
1489 } else if (agent->compatibility == NICE_COMPATIBILITY_WLM2009) {
1490 stun_agent_init (stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1491 STUN_COMPATIBILITY_MSICE2,
1492 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
1493 STUN_AGENT_USAGE_USE_FINGERPRINT);
1494 } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007) {
1495 stun_agent_init (stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1496 STUN_COMPATIBILITY_RFC3489,
1497 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
1498 STUN_AGENT_USAGE_FORCE_VALIDATER |
1499 STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES);
1500 } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
1501 stun_agent_init (stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1502 STUN_COMPATIBILITY_MSICE2,
1503 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
1504 STUN_AGENT_USAGE_USE_FINGERPRINT |
1505 STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES);
1507 stun_agent_init (stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1508 STUN_COMPATIBILITY_RFC5389,
1509 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
1510 STUN_AGENT_USAGE_USE_FINGERPRINT);
1512 stun_agent_set_software (stun_agent, agent->software_attribute);
1516 nice_agent_reset_all_stun_agents (NiceAgent *agent, gboolean only_software)
1518 GSList *stream_item, *component_item;
1520 for (stream_item = agent->streams; stream_item;
1521 stream_item = stream_item->next) {
1522 NiceStream *stream = stream_item->data;
1524 for (component_item = stream->components; component_item;
1525 component_item = component_item->next) {
1526 NiceComponent *component = component_item->data;
1529 stun_agent_set_software (&component->stun_agent,
1530 agent->software_attribute);
1532 nice_agent_init_stun_agent(agent, &component->stun_agent);
1538 nice_agent_set_property (
1541 const GValue *value,
1544 NiceAgent *agent = NICE_AGENT (object);
1548 switch (property_id)
1550 case PROP_MAIN_CONTEXT:
1551 agent->main_context = g_value_get_pointer (value);
1552 if (agent->main_context != NULL)
1553 g_main_context_ref (agent->main_context);
1556 case PROP_COMPATIBILITY:
1557 agent->compatibility = g_value_get_uint (value);
1558 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE ||
1559 agent->compatibility == NICE_COMPATIBILITY_MSN ||
1560 agent->compatibility == NICE_COMPATIBILITY_WLM2009)
1561 agent->use_ice_tcp = FALSE;
1563 nice_agent_reset_all_stun_agents (agent, FALSE);
1566 case PROP_STUN_SERVER:
1567 g_free (agent->stun_server_ip);
1568 agent->stun_server_ip = g_value_dup_string (value);
1571 case PROP_STUN_SERVER_PORT:
1572 agent->stun_server_port = g_value_get_uint (value);
1575 case PROP_CONTROLLING_MODE:
1576 priv_update_controlling_mode (agent, g_value_get_boolean (value));
1579 case PROP_FULL_MODE:
1580 agent->full_mode = g_value_get_boolean (value);
1583 case PROP_STUN_PACING_TIMER:
1584 agent->timer_ta = g_value_get_uint (value);
1587 case PROP_MAX_CONNECTIVITY_CHECKS:
1588 agent->max_conn_checks = g_value_get_uint (value);
1591 case PROP_NOMINATION_MODE:
1592 agent->nomination_mode = g_value_get_enum (value);
1595 case PROP_SUPPORT_RENOMINATION:
1596 agent->support_renomination = g_value_get_boolean (value);
1599 case PROP_IDLE_TIMEOUT:
1600 agent->idle_timeout = g_value_get_uint (value);
1604 g_free (agent->proxy_ip);
1605 agent->proxy_ip = g_value_dup_string (value);
1608 case PROP_PROXY_PORT:
1609 agent->proxy_port = g_value_get_uint (value);
1612 case PROP_PROXY_TYPE:
1613 agent->proxy_type = g_value_get_uint (value);
1616 case PROP_PROXY_USERNAME:
1617 g_free (agent->proxy_username);
1618 agent->proxy_username = g_value_dup_string (value);
1621 case PROP_PROXY_PASSWORD:
1622 g_free (agent->proxy_password);
1623 agent->proxy_password = g_value_dup_string (value);
1626 case PROP_UPNP_TIMEOUT:
1628 agent->upnp_timeout = g_value_get_uint (value);
1634 agent->upnp_enabled = g_value_get_boolean (value);
1639 agent->reliable = g_value_get_boolean (value);
1642 /* Don't allow ice-udp and ice-tcp to be disabled at the same time */
1644 if (agent->use_ice_tcp == TRUE || g_value_get_boolean (value) == TRUE)
1645 agent->use_ice_udp = g_value_get_boolean (value);
1649 if ((agent->compatibility == NICE_COMPATIBILITY_RFC5245 ||
1650 agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
1651 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
1652 (agent->use_ice_udp == TRUE || g_value_get_boolean (value) == TRUE))
1653 agent->use_ice_tcp = g_value_get_boolean (value);
1656 case PROP_BYTESTREAM_TCP:
1657 /* TODO: support bytestream mode and set property to writable */
1660 case PROP_KEEPALIVE_CONNCHECK:
1661 agent->keepalive_conncheck = g_value_get_boolean (value);
1664 case PROP_FORCE_RELAY:
1665 agent->force_relay = g_value_get_boolean (value);
1668 case PROP_STUN_MAX_RETRANSMISSIONS:
1669 agent->stun_max_retransmissions = g_value_get_uint (value);
1672 case PROP_STUN_INITIAL_TIMEOUT:
1673 agent->stun_initial_timeout = g_value_get_uint (value);
1676 case PROP_STUN_RELIABLE_TIMEOUT:
1677 agent->stun_reliable_timeout = g_value_get_uint (value);
1680 case PROP_ICE_TRICKLE:
1681 agent->use_ice_trickle = g_value_get_boolean (value);
1685 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1688 agent_unlock_and_emit (agent);
1694 agent_signal_socket_writable (NiceAgent *agent, NiceComponent *component)
1696 g_cancellable_cancel (component->tcp_writable_cancellable);
1698 agent_queue_signal (agent, signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE],
1699 component->stream_id, component->id);
1703 pseudo_tcp_socket_create (NiceAgent *agent, NiceStream *stream, NiceComponent *component)
1705 PseudoTcpCallbacks tcp_callbacks = {component,
1706 pseudo_tcp_socket_opened,
1707 pseudo_tcp_socket_readable,
1708 pseudo_tcp_socket_writable,
1709 pseudo_tcp_socket_closed,
1710 pseudo_tcp_socket_write_packet};
1711 component->tcp = pseudo_tcp_socket_new (0, &tcp_callbacks);
1712 component->tcp_writable_cancellable = g_cancellable_new ();
1713 nice_debug ("Agent %p: Create Pseudo Tcp Socket for component %d",
1714 agent, component->id);
1717 static void priv_pseudo_tcp_error (NiceAgent *agent, NiceComponent *component)
1719 if (component->tcp_writable_cancellable) {
1720 g_cancellable_cancel (component->tcp_writable_cancellable);
1721 g_clear_object (&component->tcp_writable_cancellable);
1724 if (component->tcp) {
1725 agent_signal_component_state_change (agent, component->stream_id,
1726 component->id, NICE_COMPONENT_STATE_FAILED);
1727 nice_component_detach_all_sockets (component);
1728 pseudo_tcp_socket_close (component->tcp, TRUE);
1731 if (component->tcp_clock) {
1732 g_source_destroy (component->tcp_clock);
1733 g_source_unref (component->tcp_clock);
1734 component->tcp_clock = NULL;
1739 pseudo_tcp_socket_opened (PseudoTcpSocket *sock, gpointer user_data)
1741 NiceComponent *component = user_data;
1744 agent = g_weak_ref_get (&component->agent_ref);
1748 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket Opened", agent,
1749 component->stream_id, component->id);
1751 agent_signal_socket_writable (agent, component);
1753 g_object_unref (agent);
1756 /* Will attempt to queue all @n_messages into the pseudo-TCP transmission
1757 * buffer. This is always used in reliable mode, so essentially treats @messages
1758 * as a massive flat array of buffers.
1760 * Returns the number of messages successfully sent on success (which may be
1761 * zero if sending the first buffer of the message would have blocked), or
1762 * a negative number on error. If "allow_partial" is TRUE, then it returns
1763 * the number of bytes sent
1766 pseudo_tcp_socket_send_messages (PseudoTcpSocket *self,
1767 const NiceOutputMessage *messages, guint n_messages, gboolean allow_partial,
1771 gint bytes_sent = 0;
1773 for (i = 0; i < n_messages; i++) {
1774 const NiceOutputMessage *message = &messages[i];
1777 /* If allow_partial is FALSE and there’s not enough space for the
1778 * entire message, bail now before queuing anything. This doesn’t
1779 * gel with the fact this function is only used in reliable mode,
1780 * and there is no concept of a ‘message’, but is necessary
1781 * because the calling API has no way of returning to the client
1782 * and indicating that a message was partially sent. */
1783 if (!allow_partial &&
1784 output_message_get_size (message) >
1785 pseudo_tcp_socket_get_available_send_space (self)) {
1790 (message->n_buffers >= 0 && j < (guint) message->n_buffers) ||
1791 (message->n_buffers < 0 && message->buffers[j].buffer != NULL);
1793 const GOutputVector *buffer = &message->buffers[j];
1796 /* Send on the pseudo-TCP socket. */
1797 ret = pseudo_tcp_socket_send (self, buffer->buffer, buffer->size);
1799 /* In case of -1, the error is either EWOULDBLOCK or ENOTCONN, which both
1800 * need the user to wait for the reliable-transport-writable signal */
1802 if (pseudo_tcp_socket_get_error (self) == EWOULDBLOCK)
1805 if (pseudo_tcp_socket_get_error (self) == ENOTCONN ||
1806 pseudo_tcp_socket_get_error (self) == EPIPE)
1807 g_set_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
1808 "TCP connection is not yet established.");
1810 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1811 "Error writing data to pseudo-TCP socket.");
1821 return allow_partial ? bytes_sent : (gint) i;
1824 /* Will fill up @messages from the first free byte onwards (as determined using
1825 * @iter). This is always used in reliable mode, so it essentially treats
1826 * @messages as a massive flat array of buffers.
1828 * Updates @iter in place. @iter and @messages are left in invalid states if
1829 * an error is returned.
1831 * Returns the number of valid messages in @messages on success (which may be
1832 * zero if no data is pending and the peer has disconnected), or a negative
1833 * number on error (including if the request would have blocked returning no
1836 pseudo_tcp_socket_recv_messages (PseudoTcpSocket *self,
1837 NiceInputMessage *messages, guint n_messages, NiceInputMessageIter *iter,
1840 for (; iter->message < n_messages; iter->message++) {
1841 NiceInputMessage *message = &messages[iter->message];
1843 if (iter->buffer == 0 && iter->offset == 0) {
1844 message->length = 0;
1848 (message->n_buffers >= 0 && iter->buffer < (guint) message->n_buffers) ||
1849 (message->n_buffers < 0 && message->buffers[iter->buffer].buffer != NULL);
1851 GInputVector *buffer = &message->buffers[iter->buffer];
1856 len = pseudo_tcp_socket_recv (self,
1857 (gchar *) buffer->buffer + iter->offset,
1858 buffer->size - iter->offset);
1860 nice_debug_verbose ("%s: Received %" G_GSSIZE_FORMAT " bytes into "
1861 "buffer %p (offset %" G_GSIZE_FORMAT ", length %" G_GSIZE_FORMAT
1862 ").", G_STRFUNC, len, buffer->buffer, iter->offset, buffer->size);
1867 } else if (len < 0 &&
1868 pseudo_tcp_socket_get_error (self) == EWOULDBLOCK) {
1869 /* EWOULDBLOCK. If we’ve already received something, return that;
1870 * otherwise, error. */
1871 if (nice_input_message_iter_get_n_valid_messages (iter) > 0) {
1874 g_set_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
1875 "Error reading data from pseudo-TCP socket: would block.");
1877 } else if (len < 0 && pseudo_tcp_socket_get_error (self) == ENOTCONN) {
1878 g_set_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
1879 "Error reading data from pseudo-TCP socket: not connected.");
1881 } else if (len < 0) {
1882 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1883 "Error reading data from pseudo-TCP socket.");
1886 /* Got some data! */
1887 message->length += len;
1888 iter->offset += len;
1890 } while (iter->offset < buffer->size);
1899 return nice_input_message_iter_get_n_valid_messages (iter);
1902 /* This is called with the agent lock held. */
1904 pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data)
1906 NiceComponent *component = user_data;
1908 gboolean has_io_callback;
1909 NiceStream *stream = NULL;
1910 guint stream_id = component->stream_id;
1911 guint component_id = component->id;
1913 agent = g_weak_ref_get (&component->agent_ref);
1917 if (!agent_find_component (agent, stream_id, component_id,
1918 &stream, &component)) {
1922 nice_debug_verbose ("Agent %p: s%d:%d pseudo Tcp socket readable", agent,
1923 stream_id, component->id);
1925 component->tcp_readable = TRUE;
1927 has_io_callback = nice_component_has_io_callback (component);
1929 /* Only dequeue pseudo-TCP data if we can reliably inform the client. The
1930 * agent lock is held here, so has_io_callback can only change during
1931 * nice_component_emit_io_callback(), after which it’s re-queried. This ensures
1932 * no data loss of packets already received and dequeued. */
1933 if (has_io_callback) {
1935 guint8 buf[MAX_BUFFER_SIZE];
1938 /* FIXME: Why copy into a temporary buffer here? Why can’t the I/O
1939 * callbacks be emitted directly from the pseudo-TCP receive buffer? */
1940 len = pseudo_tcp_socket_recv (sock, (gchar *) buf, sizeof(buf));
1942 nice_debug ("%s: I/O callback case: Received %" G_GSSIZE_FORMAT " bytes",
1947 component->tcp_readable = FALSE;
1948 pseudo_tcp_socket_close (component->tcp, FALSE);
1950 } else if (len < 0) {
1951 /* Handle errors. */
1952 if (pseudo_tcp_socket_get_error (sock) != EWOULDBLOCK) {
1953 nice_debug ("%s: calling priv_pseudo_tcp_error()", G_STRFUNC);
1954 priv_pseudo_tcp_error (agent, component);
1957 if (component->recv_buf_error != NULL) {
1958 GIOErrorEnum error_code;
1960 if (pseudo_tcp_socket_get_error (sock) == ENOTCONN)
1961 error_code = G_IO_ERROR_BROKEN_PIPE;
1962 else if (pseudo_tcp_socket_get_error (sock) == EWOULDBLOCK)
1963 error_code = G_IO_ERROR_WOULD_BLOCK;
1965 error_code = G_IO_ERROR_FAILED;
1967 g_set_error (component->recv_buf_error, G_IO_ERROR, error_code,
1968 "Error reading data from pseudo-TCP socket.");
1974 nice_component_emit_io_callback (agent, component, buf, len);
1976 if (!agent_find_component (agent, stream_id, component_id,
1977 &stream, &component)) {
1978 nice_debug ("Stream or Component disappeared during the callback");
1981 if (pseudo_tcp_socket_is_closed (component->tcp)) {
1982 nice_debug ("PseudoTCP socket got destroyed in readable callback!");
1986 has_io_callback = nice_component_has_io_callback (component);
1987 } while (has_io_callback);
1988 } else if (component->recv_messages != NULL) {
1989 gint n_valid_messages;
1990 GError *child_error = NULL;
1992 /* Fill up every buffer in every message until the connection closes or an
1993 * error occurs. Copy the data directly into the client’s receive message
1994 * array without making any callbacks. Update component->recv_messages_iter
1996 n_valid_messages = pseudo_tcp_socket_recv_messages (sock,
1997 component->recv_messages, component->n_recv_messages,
1998 &component->recv_messages_iter, &child_error);
2000 nice_debug_verbose ("%s: Client buffers case: Received %d valid messages:",
2001 G_STRFUNC, n_valid_messages);
2002 nice_debug_input_message_composition (component->recv_messages,
2003 component->n_recv_messages);
2005 if (n_valid_messages < 0) {
2006 g_propagate_error (component->recv_buf_error, child_error);
2008 g_clear_error (&child_error);
2011 if (n_valid_messages < 0 &&
2012 g_error_matches (child_error, G_IO_ERROR,
2013 G_IO_ERROR_WOULD_BLOCK)) {
2014 component->tcp_readable = FALSE;
2015 } else if (n_valid_messages < 0) {
2016 nice_debug ("%s: calling priv_pseudo_tcp_error()", G_STRFUNC);
2017 priv_pseudo_tcp_error (agent, component);
2018 } else if (n_valid_messages == 0) {
2020 component->tcp_readable = FALSE;
2021 pseudo_tcp_socket_close (component->tcp, FALSE);
2024 nice_debug ("%s: no data read", G_STRFUNC);
2027 if (stream && component)
2028 adjust_tcp_clock (agent, stream, component);
2032 g_object_unref (agent);
2036 pseudo_tcp_socket_writable (PseudoTcpSocket *sock, gpointer user_data)
2038 NiceComponent *component = user_data;
2041 agent = g_weak_ref_get (&component->agent_ref);
2045 nice_debug_verbose ("Agent %p: s%d:%d pseudo Tcp socket writable", agent,
2046 component->stream_id, component->id);
2048 agent_signal_socket_writable (agent, component);
2050 g_object_unref (agent);
2054 pseudo_tcp_socket_closed (PseudoTcpSocket *sock, guint32 err,
2057 NiceComponent *component = user_data;
2060 agent = g_weak_ref_get (&component->agent_ref);
2064 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket closed. "
2065 "Calling priv_pseudo_tcp_error().", agent, component->stream_id,
2067 priv_pseudo_tcp_error (agent, component);
2069 g_object_unref (agent);
2073 static PseudoTcpWriteResult
2074 pseudo_tcp_socket_write_packet (PseudoTcpSocket *psocket,
2075 const gchar *buffer, guint32 len, gpointer user_data)
2077 NiceComponent *component = user_data;
2080 agent = g_weak_ref_get (&component->agent_ref);
2084 if (component->selected_pair.local != NULL) {
2088 sock = component->selected_pair.local->sockptr;
2089 addr = &component->selected_pair.remote->addr;
2091 if (nice_debug_is_enabled ()) {
2092 gchar tmpbuf[INET6_ADDRSTRLEN];
2093 nice_address_to_string (addr, tmpbuf);
2095 nice_debug_verbose (
2096 "Agent %p : s%d:%d: sending %d bytes on socket %p (FD %d) to [%s]:%d",
2097 agent, component->stream_id, component->id, len,
2098 sock->fileno, g_socket_get_fd (sock->fileno), tmpbuf,
2099 nice_address_get_port (addr));
2102 /* Send the segment. nice_socket_send() returns 0 on EWOULDBLOCK; in that
2103 * case the segment is not sent on the wire, but we return WR_SUCCESS
2104 * anyway. This effectively drops the segment. The pseudo-TCP state machine
2105 * will eventually pick up this loss and go into recovery mode, reducing
2106 * its transmission rate and, hopefully, the usage of system resources
2107 * which caused the EWOULDBLOCK in the first place. */
2108 if (nice_socket_send (sock, addr, len, buffer) >= 0) {
2109 g_object_unref (agent);
2113 nice_debug ("%s: WARNING: Failed to send pseudo-TCP packet from agent %p "
2114 "as no pair has been selected yet.", G_STRFUNC, agent);
2117 g_object_unref (agent);
2124 notify_pseudo_tcp_socket_clock_agent_locked (NiceAgent *agent,
2127 NiceComponent *component = user_data;
2130 stream = agent_find_stream (agent, component->stream_id);
2132 return G_SOURCE_REMOVE;
2134 pseudo_tcp_socket_notify_clock (component->tcp);
2135 adjust_tcp_clock (agent, stream, component);
2137 return G_SOURCE_CONTINUE;
2141 adjust_tcp_clock (NiceAgent *agent, NiceStream *stream, NiceComponent *component)
2143 if (!pseudo_tcp_socket_is_closed (component->tcp)) {
2144 guint64 timeout = component->last_clock_timeout;
2146 if (pseudo_tcp_socket_get_next_clock (component->tcp, &timeout)) {
2147 if (timeout != component->last_clock_timeout) {
2148 component->last_clock_timeout = timeout;
2149 if (component->tcp_clock) {
2150 g_source_set_ready_time (component->tcp_clock, timeout * 1000);
2152 if (!component->tcp_clock) {
2153 long interval = timeout - (guint32) (g_get_monotonic_time () / 1000);
2155 /* Prevent integer overflows */
2156 if (interval < 0 || interval > G_MAXINT)
2157 interval = G_MAXINT;
2158 agent_timeout_add_with_context (agent, &component->tcp_clock,
2159 "Pseudo-TCP clock", interval,
2160 notify_pseudo_tcp_socket_clock_agent_locked, component);
2164 nice_debug ("Agent %p: component %d pseudo-TCP socket should be "
2165 "destroyed. Calling priv_pseudo_tcp_error().",
2166 agent, component->id);
2167 priv_pseudo_tcp_error (agent, component);
2173 _tcp_sock_is_writable (NiceSocket *sock, gpointer user_data)
2175 NiceComponent *component = user_data;
2178 agent = g_weak_ref_get (&component->agent_ref);
2184 /* Don't signal writable if the socket that has become writable is not
2185 * the selected pair */
2186 if (component->selected_pair.local == NULL ||
2187 !nice_socket_is_based_on (component->selected_pair.local->sockptr, sock)) {
2188 agent_unlock (agent);
2189 g_object_unref (agent);
2193 nice_debug ("Agent %p: s%d:%d Tcp socket writable", agent,
2194 component->stream_id, component->id);
2195 agent_signal_socket_writable (agent, component);
2197 agent_unlock_and_emit (agent);
2199 g_object_unref (agent);
2202 static const gchar *
2203 _transport_to_string (NiceCandidateTransport type) {
2205 case NICE_CANDIDATE_TRANSPORT_UDP:
2207 case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
2209 case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
2211 case NICE_CANDIDATE_TRANSPORT_TCP_SO:
2218 void agent_gathering_done (NiceAgent *agent)
2221 GSList *i, *j, *k, *l, *m;
2223 for (i = agent->streams; i; i = i->next) {
2224 NiceStream *stream = i->data;
2226 /* We ignore streams not in gathering state, typically already in
2227 * ready state. Such streams may have couples (local,remote)
2228 * candidates that have not resulted in the creation a new pair
2229 * during a previous conncheck session, and we don't want these new
2230 * pairs to be added now, because it would generate unneeded
2231 * transition changes for a stream unconcerned by this gathering.
2233 if (!stream->gathering)
2236 for (j = stream->components; j; j = j->next) {
2237 NiceComponent *component = j->data;
2239 for (k = component->local_candidates; k;) {
2240 NiceCandidate *local_candidate = k->data;
2241 GSList *next = k->next;
2243 if (agent->force_relay &&
2244 local_candidate->type != NICE_CANDIDATE_TYPE_RELAYED)
2247 if (nice_debug_is_enabled ()) {
2248 gchar tmpbuf[INET6_ADDRSTRLEN];
2249 nice_address_to_string (&local_candidate->addr, tmpbuf);
2250 nice_debug ("Agent %p: gathered %s local candidate : [%s]:%u"
2251 " for s%d/c%d. U/P '%s'/'%s'", agent,
2252 _transport_to_string (local_candidate->transport),
2253 tmpbuf, nice_address_get_port (&local_candidate->addr),
2254 local_candidate->stream_id, local_candidate->component_id,
2255 local_candidate->username, local_candidate->password);
2258 /* In addition to not contribute to the creation of a pair in the
2259 * conncheck list, according to RFC 5245, sect. 5.7.3 "Pruning the
2260 * Pairs", it can be guessed from SfB behavior, that server
2261 * reflexive pairs are expected to be also removed from the
2262 * candidates list, when pairs are formed, so they have no way to
2263 * become part of a selected pair with such type.
2265 * It can be observed that, each time a valid pair is discovered and
2266 * nominated with a local candidate of type srv-rflx, is makes SfB
2267 * fails with a 500 Internal Error.
2269 * On the contrary, when a local srv-rflx candidate is gathered,
2270 * normally announced in the sdp, but removed from the candidate
2271 * list, in that case, when the *same* candidate is discovered again
2272 * later during the conncheck, with peer-rflx type this time, then
2276 if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2 &&
2277 local_candidate->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE) {
2278 nice_debug ("Agent %p: removing this previous srv-rflx candidate "
2279 "for OC2007R2 compatibility", agent);
2280 component->local_candidates =
2281 g_slist_remove (component->local_candidates, local_candidate);
2282 agent_remove_local_candidate (agent, local_candidate);
2283 nice_candidate_free (local_candidate);
2287 for (l = component->remote_candidates; l; l = l->next) {
2288 NiceCandidate *remote_candidate = l->data;
2290 for (m = stream->conncheck_list; m; m = m->next) {
2291 CandidateCheckPair *p = m->data;
2293 if (p->local == local_candidate && p->remote == remote_candidate)
2297 conn_check_add_for_candidate_pair (agent, stream->id, component,
2298 local_candidate, remote_candidate);
2308 if (agent->discovery_timer_source == NULL &&
2309 agent->upnp_timer_source == NULL) {
2310 agent_signal_gathering_done (agent);
2313 if (agent->discovery_timer_source == NULL)
2314 agent_signal_gathering_done (agent);
2318 void agent_signal_gathering_done (NiceAgent *agent)
2322 for (i = agent->streams; i; i = i->next) {
2323 NiceStream *stream = i->data;
2324 if (stream->gathering) {
2325 stream->gathering = FALSE;
2326 agent_queue_signal (agent, signals[SIGNAL_CANDIDATE_GATHERING_DONE],
2333 agent_signal_initial_binding_request_received (NiceAgent *agent,
2336 if (stream->initial_binding_request_received != TRUE) {
2337 stream->initial_binding_request_received = TRUE;
2338 agent_queue_signal (agent, signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED],
2343 /* If the Component now has a selected_pair, and has pending TCP packets which
2344 * it couldn’t receive before due to not being able to send out ACKs (or
2345 * SYNACKs, for the initial SYN packet), handle them now.
2347 * Must be called with the agent lock held. */
2349 process_queued_tcp_packets (NiceAgent *agent, NiceStream *stream,
2350 NiceComponent *component)
2353 guint stream_id = stream->id;
2354 guint component_id = component->id;
2356 g_assert (agent->reliable);
2358 if (component->selected_pair.local == NULL ||
2359 pseudo_tcp_socket_is_closed (component->tcp) ||
2360 nice_socket_is_reliable (component->selected_pair.local->sockptr)) {
2364 nice_debug_verbose ("%s: Sending outstanding packets for agent %p.", G_STRFUNC,
2367 while ((vec = g_queue_peek_head (&component->queued_tcp_packets)) != NULL) {
2370 nice_debug ("%s: Sending %" G_GSIZE_FORMAT " bytes.", G_STRFUNC, vec->size);
2372 pseudo_tcp_socket_notify_packet (component->tcp, vec->buffer,
2375 if (!agent_find_component (agent, stream_id, component_id,
2376 &stream, &component)) {
2377 nice_debug ("Stream or Component disappeared during "
2378 "pseudo_tcp_socket_notify_packet()");
2381 if (pseudo_tcp_socket_is_closed (component->tcp)) {
2382 nice_debug ("PseudoTCP socket got destroyed in"
2383 " pseudo_tcp_socket_notify_packet()!");
2387 adjust_tcp_clock (agent, stream, component);
2390 /* Failed to send; try again later. */
2394 g_queue_pop_head (&component->queued_tcp_packets);
2395 g_free ((gpointer) vec->buffer);
2396 g_slice_free (GOutputVector, vec);
2400 void agent_signal_new_selected_pair (NiceAgent *agent, guint stream_id,
2401 guint component_id, NiceCandidate *lcandidate, NiceCandidate *rcandidate)
2403 NiceComponent *component;
2406 if (!agent_find_component (agent, stream_id, component_id,
2407 &stream, &component))
2410 if (((NiceSocket *)lcandidate->sockptr)->type == NICE_SOCKET_TYPE_UDP_TURN) {
2411 nice_udp_turn_socket_set_peer (lcandidate->sockptr, &rcandidate->addr);
2414 if(agent->reliable && !nice_socket_is_reliable (lcandidate->sockptr)) {
2415 if (!component->tcp)
2416 pseudo_tcp_socket_create (agent, stream, component);
2417 process_queued_tcp_packets (agent, stream, component);
2419 pseudo_tcp_socket_connect (component->tcp);
2420 pseudo_tcp_socket_notify_mtu (component->tcp, MAX_TCP_MTU);
2421 adjust_tcp_clock (agent, stream, component);
2424 if (nice_debug_is_enabled ()) {
2428 port = nice_address_get_port (&lcandidate->addr);
2429 nice_address_to_string (&lcandidate->addr, ip);
2431 nice_debug ("Agent %p: Local selected pair: %d:%d %s %s %s:%d %s",
2432 agent, stream_id, component_id, lcandidate->foundation,
2433 lcandidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE ?
2435 lcandidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE ?
2437 lcandidate->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "UDP" : "???",
2438 ip, port, lcandidate->type == NICE_CANDIDATE_TYPE_HOST ? "HOST" :
2439 lcandidate->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ?
2441 lcandidate->type == NICE_CANDIDATE_TYPE_RELAYED ?
2443 lcandidate->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE ?
2444 "PEER-RFLX" : "???");
2446 port = nice_address_get_port (&rcandidate->addr);
2447 nice_address_to_string (&rcandidate->addr, ip);
2449 nice_debug ("Agent %p: Remote selected pair: %d:%d %s %s %s:%d %s",
2450 agent, stream_id, component_id, rcandidate->foundation,
2451 rcandidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE ?
2453 rcandidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE ?
2455 rcandidate->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "UDP" : "???",
2456 ip, port, rcandidate->type == NICE_CANDIDATE_TYPE_HOST ? "HOST" :
2457 rcandidate->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ?
2459 rcandidate->type == NICE_CANDIDATE_TYPE_RELAYED ?
2461 rcandidate->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE ?
2462 "PEER-RFLX" : "???");
2465 agent_queue_signal (agent, signals[SIGNAL_NEW_SELECTED_PAIR_FULL],
2466 stream_id, component_id, lcandidate, rcandidate);
2467 agent_queue_signal (agent, signals[SIGNAL_NEW_SELECTED_PAIR],
2468 stream_id, component_id, lcandidate->foundation, rcandidate->foundation);
2470 if(agent->reliable && nice_socket_is_reliable (lcandidate->sockptr)) {
2471 agent_signal_socket_writable (agent, component);
2475 void agent_signal_new_candidate (NiceAgent *agent, NiceCandidate *candidate)
2477 agent_queue_signal (agent, signals[SIGNAL_NEW_CANDIDATE_FULL],
2479 agent_queue_signal (agent, signals[SIGNAL_NEW_CANDIDATE],
2480 candidate->stream_id, candidate->component_id, candidate->foundation);
2483 void agent_signal_new_remote_candidate (NiceAgent *agent, NiceCandidate *candidate)
2485 agent_queue_signal (agent, signals[SIGNAL_NEW_REMOTE_CANDIDATE_FULL],
2487 agent_queue_signal (agent, signals[SIGNAL_NEW_REMOTE_CANDIDATE],
2488 candidate->stream_id, candidate->component_id, candidate->foundation);
2491 NICEAPI_EXPORT const gchar *
2492 nice_component_state_to_string (NiceComponentState state)
2496 case NICE_COMPONENT_STATE_DISCONNECTED:
2497 return "disconnected";
2498 case NICE_COMPONENT_STATE_GATHERING:
2500 case NICE_COMPONENT_STATE_CONNECTING:
2501 return "connecting";
2502 case NICE_COMPONENT_STATE_CONNECTED:
2504 case NICE_COMPONENT_STATE_READY:
2506 case NICE_COMPONENT_STATE_FAILED:
2508 case NICE_COMPONENT_STATE_LAST:
2514 void agent_signal_component_state_change (NiceAgent *agent, guint stream_id, guint component_id, NiceComponentState new_state)
2516 NiceComponentState old_state;
2517 NiceComponent *component;
2520 g_return_if_fail (new_state < NICE_COMPONENT_STATE_LAST);
2522 if (!agent_find_component (agent, stream_id, component_id,
2523 &stream, &component))
2526 /* Validate the state change. */
2527 old_state = component->state;
2529 if (new_state == old_state) {
2533 nice_debug ("Agent %p : stream %u component %u STATE-CHANGE %s -> %s.", agent,
2534 stream_id, component_id, nice_component_state_to_string (old_state),
2535 nice_component_state_to_string (new_state));
2537 /* Check whether it’s a valid state transition. */
2538 #define TRANSITION(OLD, NEW) \
2539 (old_state == NICE_COMPONENT_STATE_##OLD && \
2540 new_state == NICE_COMPONENT_STATE_##NEW)
2542 g_assert (/* Can (almost) always transition to FAILED (including
2543 * DISCONNECTED → FAILED which happens if one component fails
2544 * before another leaves DISCONNECTED): */
2545 TRANSITION (DISCONNECTED, FAILED) ||
2546 TRANSITION (GATHERING, FAILED) ||
2547 TRANSITION (CONNECTING, FAILED) ||
2548 TRANSITION (CONNECTED, FAILED) ||
2549 TRANSITION (READY, FAILED) ||
2550 /* Standard progression towards a ready connection: */
2551 TRANSITION (DISCONNECTED, GATHERING) ||
2552 TRANSITION (GATHERING, CONNECTING) ||
2553 TRANSITION (CONNECTING, CONNECTED) ||
2554 TRANSITION (CONNECTED, READY) ||
2555 /* priv_conn_check_add_for_candidate_pair_matched(): */
2556 TRANSITION (READY, CONNECTED) ||
2557 /* If set_remote_candidates() is called with new candidates after
2558 * reaching FAILED: */
2559 TRANSITION (FAILED, CONNECTING) ||
2560 /* if new relay servers are added to a failed connection */
2561 TRANSITION (FAILED, GATHERING) ||
2562 /* Possible by calling set_remote_candidates() without calling
2563 * nice_agent_gather_candidates(): */
2564 TRANSITION (DISCONNECTED, CONNECTING));
2568 component->state = new_state;
2570 if (agent->reliable)
2571 process_queued_tcp_packets (agent, stream, component);
2573 agent_queue_signal (agent, signals[SIGNAL_COMPONENT_STATE_CHANGED],
2574 stream_id, component_id, new_state);
2578 agent_candidate_pair_priority (NiceAgent *agent, NiceCandidate *local, NiceCandidate *remote)
2580 if (agent->controlling_mode)
2581 return nice_candidate_pair_priority (local->priority, remote->priority);
2583 return nice_candidate_pair_priority (remote->priority, local->priority);
2587 priv_add_new_candidate_discovery_stun (NiceAgent *agent,
2588 NiceSocket *nicesock, NiceAddress server,
2589 NiceStream *stream, guint component_id)
2591 CandidateDiscovery *cdisco;
2593 /* note: no need to check for redundant candidates, as this is
2594 * done later on in the process */
2596 cdisco = g_slice_new0 (CandidateDiscovery);
2598 cdisco->type = NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE;
2599 cdisco->nicesock = nicesock;
2600 cdisco->server = server;
2601 cdisco->stream_id = stream->id;
2602 cdisco->component_id = component_id;
2603 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
2604 STUN_COMPATIBILITY_RFC3489,
2605 (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
2606 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) ?
2607 STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES : 0);
2609 nice_debug ("Agent %p : Adding new srv-rflx candidate discovery %p",
2612 agent->discovery_list = g_slist_append (agent->discovery_list, cdisco);
2613 ++agent->discovery_unsched_items;
2617 agent_create_tcp_turn_socket (NiceAgent *agent, NiceStream *stream,
2618 NiceComponent *component, NiceSocket *nicesock,
2619 NiceAddress *server, NiceRelayType type, gboolean reliable_tcp)
2621 NiceAddress proxy_server;
2622 NiceAddress local_address = nicesock->addr;
2624 nice_address_set_port (&local_address, 0);
2627 /* TODO: add support for turn-tcp RFC 6062 */
2628 if (agent->proxy_type != NICE_PROXY_TYPE_NONE &&
2629 agent->proxy_ip != NULL &&
2630 nice_address_set_from_string (&proxy_server, agent->proxy_ip)) {
2631 nice_address_set_port (&proxy_server, agent->proxy_port);
2632 nicesock = nice_tcp_bsd_socket_new (agent->main_context, &local_address,
2633 &proxy_server, reliable_tcp);
2636 _priv_set_socket_tos (agent, nicesock, stream->tos);
2637 if (agent->proxy_type == NICE_PROXY_TYPE_SOCKS5) {
2638 nicesock = nice_socks5_socket_new (nicesock, server,
2639 agent->proxy_username, agent->proxy_password);
2640 } else if (agent->proxy_type == NICE_PROXY_TYPE_HTTP){
2641 nicesock = nice_http_socket_new (nicesock, server,
2642 agent->proxy_username, agent->proxy_password);
2644 nice_socket_free (nicesock);
2650 if (nicesock == NULL) {
2651 nicesock = nice_tcp_bsd_socket_new (agent->main_context, &local_address,
2652 server, reliable_tcp);
2655 _priv_set_socket_tos (agent, nicesock, stream->tos);
2658 /* The TURN server may be invalid or not listening */
2659 if (nicesock == NULL)
2662 nice_socket_set_writable_callback (nicesock, _tcp_sock_is_writable,
2665 if (type == NICE_RELAY_TYPE_TURN_TLS &&
2666 agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
2667 nicesock = nice_pseudossl_socket_new (nicesock,
2668 NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_GOOGLE);
2669 } else if (type == NICE_RELAY_TYPE_TURN_TLS &&
2670 (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
2671 agent->compatibility == NICE_COMPATIBILITY_OC2007R2)) {
2672 nicesock = nice_pseudossl_socket_new (nicesock,
2673 NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC);
2675 return nice_udp_turn_over_tcp_socket_new (nicesock,
2676 agent_to_turn_socket_compatibility (agent));
2680 priv_add_new_candidate_discovery_turn (NiceAgent *agent,
2681 NiceSocket *nicesock, TurnServer *turn,
2682 NiceStream *stream, guint component_id, gboolean turn_tcp)
2684 CandidateDiscovery *cdisco;
2685 NiceComponent *component = nice_stream_find_component_by_id (stream, component_id);
2687 /* note: no need to check for redundant candidates, as this is
2688 * done later on in the process */
2690 cdisco = g_slice_new0 (CandidateDiscovery);
2691 cdisco->type = NICE_CANDIDATE_TYPE_RELAYED;
2693 if (turn->type == NICE_RELAY_TYPE_TURN_UDP) {
2694 if (agent->use_ice_udp == FALSE || turn_tcp == TRUE) {
2695 g_slice_free (CandidateDiscovery, cdisco);
2698 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
2699 NiceAddress addr = nicesock->addr;
2700 NiceSocket *new_socket;
2701 nice_address_set_port (&addr, 0);
2703 new_socket = nice_udp_bsd_socket_new (&addr);
2705 _priv_set_socket_tos (agent, new_socket, stream->tos);
2706 nice_component_attach_socket (component, new_socket);
2707 nicesock = new_socket;
2710 cdisco->nicesock = nicesock;
2712 gboolean reliable_tcp = FALSE;
2714 /* MS-TURN will allocate a transport with the same protocol it received
2715 * the allocate request. So if we are connecting in TCP, then the candidate
2716 * will be TCP-ACT/TCP-PASS which means it will be reliable all the way
2718 * [MS-TURN] : The transport address has the same transport protocol
2719 * over which the Allocate request was received; a request that is
2720 * received over TCP returns a TCP allocated transport address.
2722 /* TURN-TCP is currently unsupport unless it's OC2007 compatibliity */
2723 /* TODO: Add support for TURN-TCP */
2725 (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
2726 agent->compatibility == NICE_COMPATIBILITY_OC2007R2))
2727 reliable_tcp = TRUE;
2729 /* Ignore tcp candidates if we disabled ice-tcp */
2730 if ((agent->use_ice_udp == FALSE && reliable_tcp == FALSE) ||
2731 (agent->use_ice_tcp == FALSE && reliable_tcp == TRUE)) {
2732 g_slice_free (CandidateDiscovery, cdisco);
2736 if (turn_tcp == FALSE) {
2737 g_slice_free (CandidateDiscovery, cdisco);
2741 cdisco->nicesock = agent_create_tcp_turn_socket (agent, stream,
2742 component, nicesock, &turn->server, turn->type, reliable_tcp);
2744 nice_component_attach_socket (component, cdisco->nicesock);
2747 cdisco->turn = turn_server_ref (turn);
2748 cdisco->server = turn->server;
2750 cdisco->stream_id = stream->id;
2751 cdisco->component_id = component_id;
2753 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
2754 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
2755 STUN_COMPATIBILITY_RFC3489,
2756 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
2757 STUN_AGENT_USAGE_IGNORE_CREDENTIALS);
2758 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
2759 agent->compatibility == NICE_COMPATIBILITY_WLM2009) {
2760 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
2761 STUN_COMPATIBILITY_RFC3489,
2762 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS);
2763 } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
2764 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
2765 stun_agent_init (&cdisco->stun_agent, STUN_MSOC_KNOWN_ATTRIBUTES,
2766 STUN_COMPATIBILITY_OC2007,
2767 STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS |
2768 STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES);
2770 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
2771 STUN_COMPATIBILITY_RFC5389,
2772 STUN_AGENT_USAGE_ADD_SOFTWARE |
2773 STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS);
2775 stun_agent_set_software (&cdisco->stun_agent, agent->software_attribute);
2777 nice_debug ("Agent %p : Adding new relay-rflx candidate discovery %p",
2779 agent->discovery_list = g_slist_append (agent->discovery_list, cdisco);
2780 ++agent->discovery_unsched_items;
2783 NICEAPI_EXPORT guint
2784 nice_agent_add_stream (
2792 g_return_val_if_fail (NICE_IS_AGENT (agent), 0);
2793 g_return_val_if_fail (n_components >= 1, 0);
2796 stream = nice_stream_new (agent->next_stream_id++, n_components, agent);
2798 agent->streams = g_slist_append (agent->streams, stream);
2799 nice_debug ("Agent %p : allocating stream id %u (%p)", agent, stream->id, stream);
2800 if (agent->reliable) {
2801 nice_debug ("Agent %p : reliable stream", agent);
2802 for (i = 0; i < n_components; i++) {
2803 NiceComponent *component = nice_stream_find_component_by_id (stream, i + 1);
2805 pseudo_tcp_socket_create (agent, stream, component);
2807 nice_debug ("Agent %p: couldn't find component %d", agent, i+1);
2812 nice_stream_initialize_credentials (stream, agent->rng);
2816 agent_unlock_and_emit (agent);
2821 NICEAPI_EXPORT gboolean
2822 nice_agent_set_relay_info(NiceAgent *agent,
2823 guint stream_id, guint component_id,
2824 const gchar *server_ip, guint server_port,
2825 const gchar *username, const gchar *password,
2829 NiceComponent *component = NULL;
2830 NiceStream *stream = NULL;
2831 gboolean ret = TRUE;
2835 g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
2836 g_return_val_if_fail (stream_id >= 1, FALSE);
2837 g_return_val_if_fail (component_id >= 1, FALSE);
2838 g_return_val_if_fail (server_ip, FALSE);
2839 g_return_val_if_fail (server_port, FALSE);
2840 g_return_val_if_fail (username, FALSE);
2841 g_return_val_if_fail (password, FALSE);
2842 g_return_val_if_fail (type <= NICE_RELAY_TYPE_TURN_TLS, FALSE);
2846 if (!agent_find_component (agent, stream_id, component_id, &stream,
2852 length = g_list_length (component->turn_servers);
2853 if (length == NICE_CANDIDATE_MAX_TURN_SERVERS) {
2854 g_warning ("Agent %p : cannot have more than %d turn servers.",
2860 turn = turn_server_new (server_ip, server_port, username, password, type);
2867 nice_debug ("Agent %p: added relay server [%s]:%d of type %d to s/c %d/%d "
2868 "with user/pass : %s -- %s", agent, server_ip, server_port, type,
2869 stream_id, component_id, username,
2870 nice_debug_is_verbose() ? password : "****");
2872 /* The turn server preference (used to setup its priority in the
2873 * conncheck) is simply its position in the list. The preference must
2874 * be unique for each one.
2876 turn->preference = length;
2877 component->turn_servers = g_list_append (component->turn_servers, turn);
2879 if (stream->gathering_started) {
2882 stream->gathering = TRUE;
2884 for (i = component->local_candidates; i; i = i->next) {
2885 NiceCandidate *candidate = i->data;
2887 if (candidate->type == NICE_CANDIDATE_TYPE_HOST &&
2888 candidate->transport != NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE &&
2889 nice_address_ip_version (&candidate->addr) ==
2890 nice_address_ip_version (&turn->server))
2891 priv_add_new_candidate_discovery_turn (agent,
2892 candidate->sockptr, turn, stream, component_id,
2893 candidate->transport != NICE_CANDIDATE_TRANSPORT_UDP);
2896 if (agent->discovery_unsched_items)
2897 discovery_schedule (agent);
2903 agent_unlock_and_emit (agent);
2909 static void agent_check_upnp_gathering_done (NiceAgent *agent);
2911 static gboolean priv_upnp_timeout_cb_agent_locked (NiceAgent *agent,
2914 nice_debug ("Agent %p : UPnP port mapping timed out", agent);
2916 /* We cannot free priv->upnp here as it may be holding mappings open which
2917 * we are using (e.g. if some mappings were successful and others errored). */
2918 g_slist_free_full (agent->upnp_mapping, (GDestroyNotify) nice_address_free);
2919 agent->upnp_mapping = NULL;
2921 agent_check_upnp_gathering_done (agent);
2926 /* Check whether UPnP gathering is done, which is true when the list of pending
2927 * mappings (upnp_mapping) is empty. When it is empty, we have heard back from
2928 * gupnp-igd about each of the mappings we added, either successfully or not.
2930 * Note that upnp_mapping has to be a list, rather than a counter, as the
2931 * mapped-external-port and error-mapping-port signals could be emitted multiple
2932 * times for each mapping. */
2933 static void agent_check_upnp_gathering_done (NiceAgent *agent)
2935 if (agent->upnp_mapping != NULL)
2938 if (agent->upnp_timer_source != NULL) {
2939 g_source_destroy (agent->upnp_timer_source);
2940 g_source_unref (agent->upnp_timer_source);
2941 agent->upnp_timer_source = NULL;
2944 agent_gathering_done (agent);
2947 static void _upnp_mapped_external_port (GUPnPSimpleIgd *self, gchar *proto,
2948 gchar *external_ip, gchar *replaces_external_ip, guint external_port,
2949 gchar *local_ip, guint local_port, gchar *description, gpointer user_data)
2951 NiceAgent *agent = (NiceAgent*)user_data;
2952 NiceAddress localaddr;
2953 NiceAddress externaddr;
2954 NiceCandidateTransport transport;
2959 if (agent->upnp_timer_source == NULL)
2962 nice_debug ("Agent %p : Successfully mapped %s:%d to %s:%d", agent, local_ip,
2963 local_port, external_ip, external_port);
2965 if (!nice_address_set_from_string (&localaddr, local_ip))
2967 nice_address_set_port (&localaddr, local_port);
2969 if (g_strcmp0 (proto, "TCP") == 0)
2970 transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
2972 transport = NICE_CANDIDATE_TRANSPORT_UDP;
2974 for (i = agent->upnp_mapping; i; i = i->next) {
2975 NiceAddress *addr = i->data;
2976 if (nice_address_equal (&localaddr, addr)) {
2977 agent->upnp_mapping = g_slist_remove (agent->upnp_mapping, addr);
2978 nice_address_free (addr);
2983 if (!nice_address_set_from_string (&externaddr, external_ip))
2985 nice_address_set_port (&externaddr, external_port);
2987 for (i = agent->streams; i; i = i->next) {
2988 NiceStream *stream = i->data;
2989 for (j = stream->components; j; j = j->next) {
2990 NiceComponent *component = j->data;
2991 for (k = component->local_candidates; k; k = k->next) {
2992 NiceCandidate *local_candidate = k->data;
2994 if (agent->force_relay &&
2995 local_candidate->type != NICE_CANDIDATE_TYPE_RELAYED)
2998 if (nice_address_equal (&localaddr, &local_candidate->base_addr)) {
2999 discovery_add_server_reflexive_candidate (
3005 local_candidate->sockptr,
3014 agent_check_upnp_gathering_done (agent);
3016 agent_unlock_and_emit (agent);
3019 static void _upnp_error_mapping_port (GUPnPSimpleIgd *self, GError *error,
3020 gchar *proto, guint external_port, gchar *local_ip, guint local_port,
3021 gchar *description, gpointer user_data)
3023 NiceAgent *agent = (NiceAgent*)user_data;
3024 NiceAddress localaddr;
3029 nice_debug ("Agent %p : Error mapping %s:%d to %d (%d) : %s", agent, local_ip,
3030 local_port, external_port, error->domain, error->message);
3031 if (nice_address_set_from_string (&localaddr, local_ip)) {
3032 nice_address_set_port (&localaddr, local_port);
3034 for (i = agent->upnp_mapping; i; i = i->next) {
3035 NiceAddress *addr = i->data;
3036 if (nice_address_equal (&localaddr, addr)) {
3037 agent->upnp_mapping = g_slist_remove (agent->upnp_mapping, addr);
3038 nice_address_free (addr);
3043 agent_check_upnp_gathering_done (agent);
3046 agent_unlock_and_emit (agent);
3051 NICEAPI_EXPORT gboolean
3052 nice_agent_gather_candidates (
3059 GSList *local_addresses = NULL;
3060 gboolean ret = TRUE;
3063 g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
3064 g_return_val_if_fail (stream_id >= 1, FALSE);
3068 stream = agent_find_stream (agent, stream_id);
3069 if (stream == NULL) {
3070 agent_unlock_and_emit (agent);
3074 if (stream->gathering_started) {
3075 /* Stream is already gathering, ignore this call */
3076 agent_unlock_and_emit (agent);
3080 nice_debug ("Agent %p : In %s mode, starting candidate gathering.", agent,
3081 agent->full_mode ? "ICE-FULL" : "ICE-LITE");
3084 if (agent->upnp_enabled && agent->upnp == NULL && !agent->force_relay) {
3085 agent->upnp = gupnp_simple_igd_thread_new ();
3088 g_signal_connect (agent->upnp, "mapped-external-port",
3089 G_CALLBACK (_upnp_mapped_external_port), agent);
3090 g_signal_connect (agent->upnp, "error-mapping-port",
3091 G_CALLBACK (_upnp_error_mapping_port), agent);
3093 nice_debug ("Agent %p : Error creating UPnP Simple IGD agent", agent);
3096 nice_debug ("Agent %p : UPnP property Disabled", agent);
3099 nice_debug ("Agent %p : libnice compiled without UPnP support", agent);
3102 /* if no local addresses added, generate them ourselves */
3103 if (agent->local_addresses == NULL) {
3104 GList *addresses = nice_interfaces_get_local_ips (FALSE);
3107 for (item = addresses; item; item = g_list_next (item)) {
3108 const gchar *addr_string = item->data;
3109 NiceAddress *addr = nice_address_new ();
3111 if (nice_address_set_from_string (addr, addr_string)) {
3112 local_addresses = g_slist_append (local_addresses, addr);
3114 nice_debug ("Error: Failed to parse local address ‘%s’.", addr_string);
3115 nice_address_free (addr);
3119 g_list_free_full (addresses, (GDestroyNotify) g_free);
3121 for (i = agent->local_addresses; i; i = i->next) {
3122 NiceAddress *addr = i->data;
3123 NiceAddress *dupaddr = nice_address_dup (addr);
3125 local_addresses = g_slist_append (local_addresses, dupaddr);
3129 length = g_slist_length (local_addresses);
3130 if (length > NICE_CANDIDATE_MAX_LOCAL_ADDRESSES) {
3131 g_warning ("Agent %p : cannot have more than %d local addresses.",
3132 agent, NICE_CANDIDATE_MAX_LOCAL_ADDRESSES);
3135 for (cid = 1; cid <= stream->n_components; cid++) {
3136 NiceComponent *component = nice_stream_find_component_by_id (stream, cid);
3137 gboolean found_local_address = FALSE;
3140 ADD_HOST_UDP = ADD_HOST_MIN,
3141 ADD_HOST_TCP_ACTIVE,
3142 ADD_HOST_TCP_PASSIVE,
3143 ADD_HOST_MAX = ADD_HOST_TCP_PASSIVE
3146 if (component == NULL)
3149 /* generate a local host candidate for each local address */
3151 for (i = local_addresses;
3152 i && length < NICE_CANDIDATE_MAX_LOCAL_ADDRESSES;
3153 i = i->next, length++) {
3154 NiceAddress *addr = i->data;
3155 NiceCandidate *host_candidate;
3158 gchar local_ip[NICE_ADDRESS_STRING_LEN];
3159 nice_address_to_string (addr, local_ip);
3162 for (add_type = ADD_HOST_MIN; add_type <= ADD_HOST_MAX; add_type++) {
3163 NiceCandidateTransport transport;
3166 HostCandidateResult res = HOST_CANDIDATE_CANT_CREATE_SOCKET;
3168 if ((agent->use_ice_udp == FALSE && add_type == ADD_HOST_UDP) ||
3169 (agent->use_ice_tcp == FALSE && add_type != ADD_HOST_UDP))
3175 transport = NICE_CANDIDATE_TRANSPORT_UDP;
3177 case ADD_HOST_TCP_ACTIVE:
3178 transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
3180 case ADD_HOST_TCP_PASSIVE:
3181 transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
3185 start_port = component->min_port;
3186 if(component->min_port != 0) {
3187 start_port = nice_rng_generate_int(agent->rng, component->min_port, component->max_port+1);
3189 current_port = start_port;
3191 host_candidate = NULL;
3192 while (res == HOST_CANDIDATE_CANT_CREATE_SOCKET ||
3193 res == HOST_CANDIDATE_DUPLICATE_PORT) {
3194 nice_debug ("Agent %p: Trying to create host candidate on port %d", agent, current_port);
3195 nice_address_set_port (addr, current_port);
3196 res = discovery_add_local_host_candidate (agent, stream->id, cid,
3197 addr, transport, &host_candidate);
3198 if (current_port > 0)
3200 if (current_port > component->max_port)
3201 current_port = component->min_port;
3202 if (current_port == start_port && res != HOST_CANDIDATE_DUPLICATE_PORT)
3204 if (current_port == 0 && res != HOST_CANDIDATE_DUPLICATE_PORT)
3208 if (res == HOST_CANDIDATE_REDUNDANT) {
3209 nice_debug ("Agent %p: Ignoring local candidate, it's redundant",
3212 } else if (res == HOST_CANDIDATE_FAILED) {
3213 nice_debug ("Agent %p: Could not retrieve component %d/%d", agent,
3216 } else if (res == HOST_CANDIDATE_CANT_CREATE_SOCKET) {
3217 if (nice_debug_is_enabled ()) {
3218 gchar ip[NICE_ADDRESS_STRING_LEN];
3219 nice_address_to_string (addr, ip);
3220 nice_debug ("Agent %p: Unable to add local host candidate %s for"
3221 " s%d:%d. Invalid interface?", agent, ip, stream->id,
3225 } else if (res == HOST_CANDIDATE_DUPLICATE_PORT) {
3226 nice_debug ("Agent %p: Ignoring local candidate, duplicate port",
3231 found_local_address = TRUE;
3232 nice_address_set_port (addr, 0);
3234 nice_socket_set_writable_callback (host_candidate->sockptr,
3235 _tcp_sock_is_writable, component);
3238 if (agent->upnp_enabled && agent->upnp &&
3239 transport != NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) {
3240 NiceAddress *base_addr = nice_address_dup (&host_candidate->base_addr);
3241 nice_debug ("Agent %p: Adding UPnP port %s:%d", agent, local_ip,
3242 nice_address_get_port (base_addr));
3243 gupnp_simple_igd_add_port (GUPNP_SIMPLE_IGD (agent->upnp),
3244 transport == NICE_CANDIDATE_TRANSPORT_UDP ? "UDP" : "TCP",
3245 0, local_ip, nice_address_get_port (base_addr),
3247 agent->upnp_mapping = g_slist_prepend (agent->upnp_mapping, base_addr);
3249 agent_timeout_add_with_context (agent, &agent->upnp_timer_source,
3250 "UPnP timeout", agent->upnp_timeout,
3251 priv_upnp_timeout_cb_agent_locked, agent);
3255 /* TODO: Add server-reflexive support for TCP candidates */
3256 if (agent->full_mode && agent->stun_server_ip && !agent->force_relay &&
3257 transport == NICE_CANDIDATE_TRANSPORT_UDP) {
3258 NiceAddress stun_server;
3259 if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
3260 nice_address_set_port (&stun_server, agent->stun_server_port);
3262 if (nice_address_ip_version (&host_candidate->addr) ==
3263 nice_address_ip_version (&stun_server))
3264 priv_add_new_candidate_discovery_stun (agent,
3265 host_candidate->sockptr,
3272 if (agent->full_mode && component &&
3273 transport != NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) {
3275 int host_ip_version = nice_address_ip_version (&host_candidate->addr);
3277 for (item = component->turn_servers; item; item = item->next) {
3278 TurnServer *turn = item->data;
3280 if (host_ip_version != nice_address_ip_version (&turn->server)) {
3284 priv_add_new_candidate_discovery_turn (agent,
3285 host_candidate->sockptr,
3289 host_candidate->transport != NICE_CANDIDATE_TRANSPORT_UDP);
3294 /* Go to error if we could not find a local address for a given
3297 if (!found_local_address) {
3303 stream->gathering = TRUE;
3304 stream->gathering_started = TRUE;
3306 /* Only signal the new candidates after we're sure that the gathering was
3307 * succesfful. But before sending gathering-done */
3308 for (cid = 1; cid <= stream->n_components; cid++) {
3309 NiceComponent *component = nice_stream_find_component_by_id (stream, cid);
3310 for (i = component->local_candidates; i; i = i->next) {
3311 NiceCandidate *candidate = i->data;
3313 if (agent->force_relay && candidate->type != NICE_CANDIDATE_TYPE_RELAYED)
3316 agent_signal_new_candidate (agent, candidate);
3320 /* note: no async discoveries pending, signal that we are ready */
3321 if (agent->discovery_unsched_items == 0 &&
3323 agent->upnp_mapping == NULL) {
3327 nice_debug ("Agent %p: Candidate gathering FINISHED, no scheduled items.",
3329 agent_gathering_done (agent);
3330 } else if (agent->discovery_unsched_items) {
3331 discovery_schedule (agent);
3335 for (i = local_addresses; i; i = i->next)
3336 nice_address_free (i->data);
3337 g_slist_free (local_addresses);
3340 priv_stop_upnp (agent);
3341 for (cid = 1; cid <= stream->n_components; cid++) {
3342 NiceComponent *component = nice_stream_find_component_by_id (stream, cid);
3344 nice_component_free_socket_sources (component);
3346 for (i = component->local_candidates; i; i = i->next) {
3347 NiceCandidate *candidate = i->data;
3349 agent_remove_local_candidate (agent, candidate);
3351 nice_candidate_free (candidate);
3353 g_slist_free (component->local_candidates);
3354 component->local_candidates = NULL;
3356 discovery_prune_stream (agent, stream_id);
3359 agent_unlock_and_emit (agent);
3364 void agent_remove_local_candidate (NiceAgent *agent, NiceCandidate *candidate)
3367 gchar local_ip[NICE_ADDRESS_STRING_LEN];
3369 if (agent->upnp == NULL)
3372 if (candidate->type != NICE_CANDIDATE_TYPE_HOST)
3375 if (nice_address_get_port (&candidate->addr) == 0)
3378 nice_address_to_string (&candidate->addr, local_ip);
3380 gupnp_simple_igd_remove_port_local (GUPNP_SIMPLE_IGD (agent->upnp), "UDP",
3381 local_ip, nice_address_get_port (&candidate->addr));
3385 static void priv_stop_upnp (NiceAgent *agent)
3391 g_slist_free_full (agent->upnp_mapping, (GDestroyNotify) nice_address_free);
3392 agent->upnp_mapping = NULL;
3394 if (agent->upnp_timer_source != NULL) {
3395 g_source_destroy (agent->upnp_timer_source);
3396 g_source_unref (agent->upnp_timer_source);
3397 agent->upnp_timer_source = NULL;
3402 static void priv_remove_keepalive_timer (NiceAgent *agent)
3404 if (agent->keepalive_timer_source != NULL) {
3405 g_source_destroy (agent->keepalive_timer_source);
3406 g_source_unref (agent->keepalive_timer_source);
3407 agent->keepalive_timer_source = NULL;
3412 on_stream_refreshes_pruned (NiceAgent *agent, NiceStream *stream)
3414 // This is called from a timeout cb with agent lock held
3416 nice_stream_close (agent, stream);
3418 agent->pruning_streams = g_slist_remove (agent->pruning_streams, stream);
3420 agent_unlock (agent);
3422 /* Actually free the stream. This should be done with the lock released, as
3423 * it could end up disposing of a NiceIOStream, which tries to take the
3424 * agent lock itself. */
3425 g_object_unref (stream);
3429 return G_SOURCE_REMOVE;
3433 nice_agent_remove_stream (
3437 guint stream_ids[] = { stream_id, 0 };
3439 /* note that streams/candidates can be in use by other threads */
3443 g_return_if_fail (NICE_IS_AGENT (agent));
3444 g_return_if_fail (stream_id >= 1);
3447 stream = agent_find_stream (agent, stream_id);
3450 agent_unlock_and_emit (agent);
3454 /* note: remove items with matching stream_ids from both lists */
3455 conn_check_prune_stream (agent, stream);
3456 discovery_prune_stream (agent, stream_id);
3457 refresh_prune_stream_async (agent, stream,
3458 (NiceTimeoutLockedCallback) on_stream_refreshes_pruned);
3460 agent->pruning_streams = g_slist_prepend (agent->pruning_streams, stream);
3462 /* Remove the stream and signal its removal. */
3463 agent->streams = g_slist_remove (agent->streams, stream);
3465 if (!agent->streams)
3466 priv_remove_keepalive_timer (agent);
3468 agent_queue_signal (agent, signals[SIGNAL_STREAMS_REMOVED],
3469 g_memdup (stream_ids, sizeof(stream_ids)));
3471 agent_unlock_and_emit (agent);
3475 nice_agent_set_port_range (NiceAgent *agent, guint stream_id, guint component_id,
3476 guint min_port, guint max_port)
3479 NiceComponent *component;
3481 g_return_if_fail (NICE_IS_AGENT (agent));
3482 g_return_if_fail (stream_id >= 1);
3483 g_return_if_fail (component_id >= 1);
3487 if (agent_find_component (agent, stream_id, component_id, &stream,
3489 if (stream->gathering_started) {
3490 g_critical ("nice_agent_gather_candidates (stream_id=%u) already called for this stream", stream_id);
3492 component->min_port = min_port;
3493 component->max_port = max_port;
3497 agent_unlock_and_emit (agent);
3500 NICEAPI_EXPORT gboolean
3501 nice_agent_add_local_address (NiceAgent *agent, NiceAddress *addr)
3503 NiceAddress *dupaddr;
3505 g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
3506 g_return_val_if_fail (addr != NULL, FALSE);
3510 dupaddr = nice_address_dup (addr);
3511 nice_address_set_port (dupaddr, 0);
3512 agent->local_addresses = g_slist_append (agent->local_addresses, dupaddr);
3514 agent_unlock_and_emit (agent);
3518 /* Recompute foundations of all candidate pairs from a given stream
3519 * having a specific remote candidate, and eventually update the
3520 * priority of the selected pair as well.
3522 static void priv_update_pair_foundations (NiceAgent *agent,
3523 guint stream_id, guint component_id, NiceCandidate *remote)
3526 NiceComponent *component;
3528 if (agent_find_component (agent, stream_id, component_id, &stream,
3532 for (i = stream->conncheck_list; i; i = i->next) {
3533 CandidateCheckPair *pair = i->data;
3535 if (pair->remote == remote) {
3536 gchar foundation[NICE_CANDIDATE_PAIR_MAX_FOUNDATION];
3537 g_snprintf (foundation, NICE_CANDIDATE_PAIR_MAX_FOUNDATION, "%s:%s",
3538 pair->local->foundation, pair->remote->foundation);
3539 if (strncmp (pair->foundation, foundation,
3540 NICE_CANDIDATE_PAIR_MAX_FOUNDATION)) {
3541 g_strlcpy (pair->foundation, foundation,
3542 NICE_CANDIDATE_PAIR_MAX_FOUNDATION);
3543 nice_debug ("Agent %p : Updating pair %p foundation to '%s'",
3544 agent, pair, pair->foundation);
3545 if (pair->state == NICE_CHECK_SUCCEEDED)
3546 conn_check_unfreeze_related (agent, pair);
3547 if (component->selected_pair.local == pair->local &&
3548 component->selected_pair.remote == pair->remote) {
3549 gchar priority[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE];
3551 /* the foundation update of the selected pair also implies
3552 * an update of its priority. stun_priority doesn't change
3553 * because only the remote candidate foundation is modified.
3555 nice_debug ("Agent %p : pair %p is the selected pair, updating "
3556 "its priority.", agent, pair);
3557 component->selected_pair.priority = pair->priority;
3559 nice_candidate_pair_priority_to_string (pair->priority, priority);
3560 nice_debug ("Agent %p : updating SELECTED PAIR for component "
3561 "%u: %s (prio:%s).", agent,
3562 component->id, foundation, priority);
3563 agent_signal_new_selected_pair (agent, pair->stream_id,
3564 component->id, pair->local, pair->remote);
3572 /* Returns the nominated pair with the highest priority.
3574 static CandidateCheckPair *priv_get_highest_priority_nominated_pair (
3575 NiceAgent *agent, guint stream_id, guint component_id)
3578 NiceComponent *component;
3579 CandidateCheckPair *pair;
3582 if (agent_find_component (agent, stream_id, component_id, &stream,
3585 for (i = stream->conncheck_list; i; i = i->next) {
3587 if (pair->component_id == component_id && pair->nominated) {
3595 static gboolean priv_add_remote_candidate (
3599 NiceCandidateType type,
3600 const NiceAddress *addr,
3601 const NiceAddress *base_addr,
3602 NiceCandidateTransport transport,
3604 const gchar *username,
3605 const gchar *password,
3606 const gchar *foundation)
3609 NiceComponent *component;
3610 NiceCandidate *candidate;
3611 CandidateCheckPair *pair;
3613 if (transport == NICE_CANDIDATE_TRANSPORT_UDP &&
3614 !agent->use_ice_udp)
3616 if (transport != NICE_CANDIDATE_TRANSPORT_UDP &&
3617 !agent->use_ice_tcp)
3620 if (!agent_find_component (agent, stream_id, component_id, &stream,
3624 /* step: check whether the candidate already exists */
3625 candidate = nice_component_find_remote_candidate (component, addr, transport);
3627 /* If it was a discovered remote peer reflexive candidate, then it should
3628 * be updated according to RFC 5245 section 7.2.1.3 */
3629 if (candidate && candidate->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
3630 nice_debug ("Agent %p : Updating existing peer-rfx remote candidate to %s",
3631 agent, _cand_type_to_sdp (type));
3632 candidate->type = type;
3633 /* The updated candidate is no more peer reflexive, so its
3634 * sockptr can be cleared
3636 candidate->sockptr = NULL;
3637 /* If it got there, the next one will also be ran, so the foundation
3642 if (candidate && candidate->type == type) {
3643 if (nice_debug_is_enabled ()) {
3644 gchar tmpbuf[INET6_ADDRSTRLEN];
3645 nice_address_to_string (addr, tmpbuf);
3646 nice_debug ("Agent %p : Updating existing remote candidate with addr [%s]:%u"
3647 " for s%d/c%d. U/P '%s'/'%s' prio: %08x", agent, tmpbuf,
3648 nice_address_get_port (addr), stream_id, component_id,
3649 username, password, priority);
3651 /* case 1: an existing candidate, update the attributes */
3653 candidate->base_addr = *base_addr;
3654 candidate->priority = priority;
3656 g_strlcpy(candidate->foundation, foundation,
3657 NICE_CANDIDATE_MAX_FOUNDATION);
3658 /* note: username and password must remain the same during
3659 * a session; see sect 9.1.2 in ICE ID-19 */
3661 /* note: however, the user/pass in ID-19 is global, if the user/pass
3662 * are set in the candidate here, it means they need to be updated...
3663 * this is essential to overcome a race condition where we might receive
3664 * a valid binding request from a valid candidate that wasn't yet added to
3665 * our list of candidates.. this 'update' will make the peer-rflx a
3666 * server-rflx/host candidate again */
3668 if (candidate->username == NULL)
3669 candidate->username = g_strdup (username);
3670 else if (g_strcmp0 (username, candidate->username))
3671 nice_debug ("Agent %p : Candidate username '%s' is not allowed "
3672 "to change to '%s' now (ICE restart only).", agent,
3673 candidate->username, username);
3676 if (candidate->password == NULL)
3677 candidate->password = g_strdup (password);
3678 else if (g_strcmp0 (password, candidate->password))
3679 nice_debug ("Agent %p : candidate password '%s' is not allowed "
3680 "to change to '%s' now (ICE restart only).", agent,
3681 candidate->password, password);
3684 /* since the type of the existing candidate may have changed,
3685 * the pairs priority and foundation related to this candidate need
3686 * to be recomputed...
3688 recalculate_pair_priorities (agent);
3689 priv_update_pair_foundations (agent, stream_id, component_id, candidate);
3690 /* ... and maybe we now have another nominated pair with a higher
3691 * priority as the result of this priorities update.
3693 pair = priv_get_highest_priority_nominated_pair (agent,
3694 stream_id, component_id);
3696 (pair->local != component->selected_pair.local ||
3697 pair->remote != component->selected_pair.remote)) {
3698 /* If we have (at least) one pair with the nominated flag set, it
3699 * implies that this pair (or another) is set as the selected pair
3700 * for this component. In other words, this is really an *update*
3701 * of the selected pair.
3703 g_assert (component->selected_pair.local != NULL);
3704 g_assert (component->selected_pair.remote != NULL);
3705 nice_debug ("Agent %p : Updating selected pair with higher "
3706 "priority nominated pair %p.", agent, pair);
3707 conn_check_update_selected_pair (agent, component, pair);
3709 conn_check_update_check_list_state_for_ready (agent, stream, component);
3712 /* case 2: add a new candidate */
3714 if (type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
3715 nice_debug("Agent %p : Warning: ignoring externally set peer-reflexive candidate!", agent);
3718 candidate = nice_candidate_new (type);
3720 candidate->stream_id = stream_id;
3721 candidate->component_id = component_id;
3723 candidate->type = type;
3725 candidate->addr = *addr;
3727 if (nice_debug_is_enabled ()) {
3728 gchar tmpbuf[INET6_ADDRSTRLEN] = {0};
3730 nice_address_to_string (addr, tmpbuf);
3731 nice_debug ("Agent %p : Adding %s remote candidate with addr [%s]:%u"
3732 " for s%d/c%d. U/P '%s'/'%s' prio: %08x", agent,
3733 _transport_to_string (transport), tmpbuf,
3734 addr? nice_address_get_port (addr) : 0, stream_id, component_id,
3735 username, password, priority);
3738 if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
3739 /* note: If there are TCP candidates for a media stream,
3740 * a controlling agent MUST use the regular selection algorithm,
3741 * RFC 6544, sect 8, "Concluding ICE Processing"
3743 if (agent->controlling_mode &&
3744 agent->nomination_mode == NICE_NOMINATION_MODE_AGGRESSIVE &&
3745 transport != NICE_CANDIDATE_TRANSPORT_UDP) {
3746 if (conn_check_stun_transactions_count (agent) > 0) {
3747 /* changing nomination mode from aggressive to regular while
3748 * conncheck is ongoing may cause unexpected results (inflight
3749 * aggressive stun requests may nominate a pair unilaterally)
3751 nice_debug ("Agent %p : we have a TCP candidate, but conncheck "
3752 "has started already in aggressive mode, ignore it", agent);
3755 nice_debug ("Agent %p : we have a TCP candidate, switching back "
3756 "to regular nomination mode", agent);
3757 agent->nomination_mode = NICE_NOMINATION_MODE_REGULAR;
3763 candidate->base_addr = *base_addr;
3765 candidate->transport = transport;
3766 candidate->priority = priority;
3767 candidate->username = g_strdup (username);
3768 candidate->password = g_strdup (password);
3771 g_strlcpy (candidate->foundation, foundation,
3772 NICE_CANDIDATE_MAX_FOUNDATION);
3774 /* We only create a pair when a candidate is new, and not when
3775 * updating an existing one.
3777 if (conn_check_add_for_candidate (agent, stream_id,
3778 component, candidate) < 0)
3781 component->remote_candidates = g_slist_append (component->remote_candidates,
3787 nice_candidate_free (candidate);
3791 NICEAPI_EXPORT gboolean
3792 nice_agent_set_remote_credentials (
3795 const gchar *ufrag, const gchar *pwd)
3798 gboolean ret = FALSE;
3800 g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
3801 g_return_val_if_fail (stream_id >= 1, FALSE);
3803 nice_debug ("Agent %p: set_remote_credentials %d", agent, stream_id);
3807 stream = agent_find_stream (agent, stream_id);
3808 /* note: oddly enough, ufrag and pwd can be empty strings */
3809 if (stream && ufrag && pwd) {
3811 g_strlcpy (stream->remote_ufrag, ufrag, NICE_STREAM_MAX_UFRAG);
3812 g_strlcpy (stream->remote_password, pwd, NICE_STREAM_MAX_PWD);
3814 conn_check_remote_credentials_set(agent, stream);
3821 agent_unlock_and_emit (agent);
3825 NICEAPI_EXPORT gboolean
3826 nice_agent_set_local_credentials (
3833 gboolean ret = FALSE;
3835 g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
3836 g_return_val_if_fail (stream_id >= 1, FALSE);
3840 stream = agent_find_stream (agent, stream_id);
3842 /* note: oddly enough, ufrag and pwd can be empty strings */
3843 if (stream && ufrag && pwd) {
3844 g_strlcpy (stream->local_ufrag, ufrag, NICE_STREAM_MAX_UFRAG);
3845 g_strlcpy (stream->local_password, pwd, NICE_STREAM_MAX_PWD);
3852 agent_unlock_and_emit (agent);
3857 NICEAPI_EXPORT gboolean
3858 nice_agent_get_local_credentials (
3861 gchar **ufrag, gchar **pwd)
3864 gboolean ret = TRUE;
3866 g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
3867 g_return_val_if_fail (stream_id >= 1, FALSE);
3871 stream = agent_find_stream (agent, stream_id);
3872 if (stream == NULL) {
3876 if (!ufrag || !pwd) {
3880 *ufrag = g_strdup (stream->local_ufrag);
3881 *pwd = g_strdup (stream->local_password);
3886 agent_unlock_and_emit (agent);
3891 _set_remote_candidates_locked (NiceAgent *agent, NiceStream *stream,
3892 NiceComponent *component, const GSList *candidates)
3897 for (i = candidates; i && added >= 0; i = i->next) {
3898 NiceCandidate *d = (NiceCandidate*) i->data;
3900 if (nice_address_is_valid (&d->addr) == TRUE) {
3902 priv_add_remote_candidate (agent,
3919 conn_check_remote_candidates_set(agent, stream, component);
3920 conn_check_schedule_next (agent);
3928 nice_agent_set_remote_candidates (NiceAgent *agent, guint stream_id, guint component_id, const GSList *candidates)
3932 NiceComponent *component;
3934 g_return_val_if_fail (NICE_IS_AGENT (agent), 0);
3935 g_return_val_if_fail (stream_id >= 1, 0);
3936 g_return_val_if_fail (component_id >= 1, 0);
3938 nice_debug ("Agent %p: set_remote_candidates %d %d", agent, stream_id, component_id);
3942 if (!agent_find_component (agent, stream_id, component_id,
3943 &stream, &component)) {
3944 g_warning ("Could not find component %u in stream %u", component_id,
3950 added = _set_remote_candidates_locked (agent, stream, component, candidates);
3953 agent_unlock_and_emit (agent);
3958 /* Return values for agent_recv_message_unlocked(). Needed purely because it
3959 * must differentiate between RECV_OOB and RECV_SUCCESS. */
3962 RECV_WOULD_BLOCK = -1,
3968 * agent_recv_message_unlocked:
3969 * @agent: a #NiceAgent
3970 * @stream: the stream to receive from
3971 * @component: the component to receive from
3972 * @socket: the socket to receive on
3973 * @message: the message to write into (must have at least 65536 bytes of buffer
3976 * Receive a single message of data from the given @stream, @component and
3977 * @socket tuple, in a non-blocking fashion. The caller must ensure that
3978 * @message contains enough buffers to provide at least 65536 bytes of buffer
3979 * space, but the buffers may be split as the caller sees fit.
3981 * This must be called with the agent’s lock held.
3983 * Returns: number of valid messages received on success (i.e. %RECV_SUCCESS or
3984 * 1), %RECV_OOB if data was successfully received but was handled out-of-band
3985 * (e.g. due to being a STUN control packet), %RECV_WOULD_BLOCK if no data is
3986 * available and the call would block, or %RECV_ERROR on error
3989 agent_recv_message_unlocked (
3992 NiceComponent *component,
3993 NiceSocket *nicesock,
3994 NiceInputMessage *message)
4000 gboolean is_turn = FALSE;
4002 /* We need an address for packet parsing, below. */
4003 if (message->from == NULL) {
4004 message->from = &from;
4007 /* ICE-TCP requires that all packets be framed with RFC4571 */
4008 if (nice_socket_is_reliable (nicesock)) {
4009 /* In the case of OC2007 and OC2007R2 which uses UDP TURN for TCP-ACTIVE
4010 * and TCP-PASSIVE candidates, the recv_messages will be packetized and
4011 * always return an entire frame, so we must read it as is */
4012 if (nicesock->type == NICE_SOCKET_TYPE_UDP_TURN_OVER_TCP ||
4013 nicesock->type == NICE_SOCKET_TYPE_UDP_TURN) {
4015 GInputVector *local_bufs;
4016 NiceInputMessage local_message;
4018 guint16 rfc4571_frame;
4021 /* In case of ICE-TCP on UDP-TURN (OC2007 compat), we need to do the recv
4022 * on the UDP_TURN socket, but it's possible we receive the source event
4023 * on the UDP_TURN_OVER_TCP socket, so in that case, we need to replace
4024 * the socket we do the recv on to the topmost socket
4026 for (cand_i = component->local_candidates; cand_i; cand_i = cand_i->next) {
4027 NiceCandidate *cand = cand_i->data;
4029 if (cand->type == NICE_CANDIDATE_TYPE_RELAYED &&
4030 cand->stream_id == stream->id &&
4031 cand->component_id == component->id &&
4032 nice_socket_is_based_on(cand->sockptr, nicesock)) {
4033 nice_debug ("Agent %p : Packet received from a TURN socket.",
4035 nicesock = cand->sockptr;
4039 /* Count the number of buffers. */
4040 if (message->n_buffers == -1) {
4041 for (i = 0; message->buffers[i].buffer != NULL; i++)
4044 n_bufs = message->n_buffers;
4047 local_bufs = g_alloca ((n_bufs + 1) * sizeof (GInputVector));
4048 local_message.buffers = local_bufs;
4049 local_message.n_buffers = n_bufs + 1;
4050 local_message.from = message->from;
4051 local_message.length = 0;
4053 local_bufs[0].buffer = &rfc4571_frame;
4054 local_bufs[0].size = sizeof (guint16);
4056 for (i = 0; i < n_bufs; i++) {
4057 local_bufs[i + 1].buffer = message->buffers[i].buffer;
4058 local_bufs[i + 1].size = message->buffers[i].size;
4060 sockret = nice_socket_recv_messages (nicesock, &local_message, 1);
4061 if (sockret == 1 && local_message.length >= sizeof (guint16)) {
4062 message->length = ntohs (rfc4571_frame);
4065 if (nicesock->type == NICE_SOCKET_TYPE_TCP_PASSIVE) {
4066 NiceSocket *new_socket;
4068 /* Passive candidates when readable should accept and create a new
4069 * socket. When established, the connchecks will create a peer reflexive
4070 * candidate for it */
4071 new_socket = nice_tcp_passive_socket_accept (nicesock);
4073 _priv_set_socket_tos (agent, new_socket, stream->tos);
4074 nice_debug ("Agent %p: add to tcp-pass socket %p a new "
4075 "tcp accept socket %p in s/c %d/%d",
4076 agent, nicesock, new_socket, stream->id, component->id);
4077 nice_component_attach_socket (component, new_socket);
4081 /* In the case of a real ICE-TCP connection, we can use the socket as a
4082 * bytestream and do the read here with caching of data being read
4084 gssize available = g_socket_get_available_bytes (nicesock->fileno);
4086 /* TODO: Support bytestream reads */
4087 message->length = 0;
4089 if (available <= 0) {
4090 sockret = available;
4092 /* If we don't call check_connect_result on an outbound connection,
4093 * then is_connected will always return FALSE. That's why we check
4094 * both conditions to make sure g_socket_is_connected returns the
4095 * correct result, otherwise we end up closing valid connections
4097 if (g_socket_check_connect_result (nicesock->fileno, NULL) == FALSE ||
4098 g_socket_is_connected (nicesock->fileno) == FALSE) {
4099 /* If we receive a readable event on a TCP_BSD socket which is
4100 * not connected, it means that it failed to connect, so we must
4101 * return an error to make the socket fail/closed
4105 gint flags = G_SOCKET_MSG_PEEK;
4107 /* If available bytes are 0, but the socket is still considered
4108 * connected, then either we're just trying to see if there's more
4109 * data available or the peer closed the connection.
4110 * The only way to know is to do a read, so we do here a peek and
4111 * check the return value, if it's 0, it means the peer has closed
4112 * the connection, so we must return an error instead of WOULD_BLOCK
4114 if (g_socket_receive_message (nicesock->fileno, NULL,
4115 NULL, 0, NULL, NULL, &flags, NULL, NULL) == 0)
4118 } else if (agent->rfc4571_expecting_length == 0) {
4119 if ((gsize) available >= sizeof(guint16)) {
4120 guint16 rfc4571_frame;
4121 GInputVector local_buf = { &rfc4571_frame, sizeof(guint16)};
4122 NiceInputMessage local_message = { &local_buf, 1, message->from, 0};
4124 sockret = nice_socket_recv_messages (nicesock, &local_message, 1);
4125 if (sockret == 1 && local_message.length >= sizeof (guint16)) {
4126 agent->rfc4571_expecting_length = ntohs (rfc4571_frame);
4127 available = g_socket_get_available_bytes (nicesock->fileno);
4131 if (agent->rfc4571_expecting_length > 0 &&
4132 available >= agent->rfc4571_expecting_length) {
4133 GInputVector *local_bufs;
4134 NiceInputMessage local_message;
4139 /* Count the number of buffers. */
4140 if (message->n_buffers == -1) {
4141 for (i = 0; message->buffers[i].buffer != NULL; i++)
4144 n_bufs = message->n_buffers;
4147 local_bufs = g_alloca (n_bufs * sizeof (GInputVector));
4148 local_message.buffers = local_bufs;
4149 local_message.from = message->from;
4150 local_message.length = 0;
4151 local_message.n_buffers = 0;
4153 /* Only read up to the expected number of bytes in the frame */
4155 for (i = 0; i < n_bufs; i++) {
4156 if (message->buffers[i].size < agent->rfc4571_expecting_length - off) {
4157 local_bufs[i].buffer = message->buffers[i].buffer;
4158 local_bufs[i].size = message->buffers[i].size;
4159 local_message.n_buffers++;
4160 off += message->buffers[i].size;
4162 local_bufs[i].buffer = message->buffers[i].buffer;
4163 local_bufs[i].size = MIN (message->buffers[i].size,
4164 agent->rfc4571_expecting_length - off);
4165 local_message.n_buffers++;
4166 off += local_bufs[i].size;
4169 sockret = nice_socket_recv_messages (nicesock, &local_message, 1);
4171 message->length = local_message.length;
4172 agent->rfc4571_expecting_length -= local_message.length;
4178 sockret = nice_socket_recv_messages (nicesock, message, 1);
4182 retval = RECV_WOULD_BLOCK; /* EWOULDBLOCK */
4183 nice_debug_verbose ("%s: Agent %p: no message available on read attempt",
4186 } else if (sockret < 0) {
4187 nice_debug ("Agent %p: %s returned %d, errno (%d) : %s",
4188 agent, G_STRFUNC, sockret, errno, g_strerror (errno));
4190 retval = RECV_ERROR;
4196 g_assert_cmpint (retval, !=, RECV_OOB);
4197 if (message->length == 0) {
4199 nice_debug_verbose ("%s: Agent %p: message handled out-of-band", G_STRFUNC,
4204 if (nice_debug_is_verbose ()) {
4205 gchar tmpbuf[INET6_ADDRSTRLEN];
4206 nice_address_to_string (message->from, tmpbuf);
4207 nice_debug_verbose ("%s: Agent %p : Packet received on local socket %p "
4208 "(fd %d) from [%s]:%u (%" G_GSSIZE_FORMAT " octets).", G_STRFUNC, agent,
4209 nicesock, nicesock->fileno ? g_socket_get_fd (nicesock->fileno) : -1, tmpbuf,
4210 nice_address_get_port (message->from), message->length);
4213 if (nicesock->type == NICE_SOCKET_TYPE_UDP_TURN)
4216 if (!is_turn && component->turn_candidate &&
4217 nice_socket_is_based_on (component->turn_candidate->sockptr, nicesock) &&
4218 nice_address_equal (message->from,
4219 &component->turn_candidate->turn->server)) {
4221 retval = nice_udp_turn_socket_parse_recv_message (
4222 component->turn_candidate->sockptr, &nicesock, message);
4225 for (item = component->turn_servers; item && !is_turn;
4226 item = g_list_next (item)) {
4227 TurnServer *turn = item->data;
4230 if (!nice_address_equal (message->from, &turn->server))
4233 nice_debug_verbose ("Agent %p : Packet received from TURN server candidate.",
4237 for (i = component->local_candidates; i; i = i->next) {
4238 NiceCandidate *cand = i->data;
4240 if (cand->type == NICE_CANDIDATE_TYPE_RELAYED &&
4241 cand->turn == turn &&
4242 cand->stream_id == stream->id &&
4243 nice_socket_is_based_on (cand->sockptr, nicesock)) {
4244 retval = nice_udp_turn_socket_parse_recv_message (cand->sockptr, &nicesock,
4252 if (agent->force_relay && !is_turn) {
4253 /* Ignore messages not from TURN if TURN is required */
4254 retval = RECV_WOULD_BLOCK; /* EWOULDBLOCK */
4258 if (retval == RECV_OOB)
4261 /* If the message’s stated length is equal to its actual length, it’s probably
4262 * a STUN message; otherwise it’s probably data. */
4263 if (stun_message_validate_buffer_length_fast (
4264 (StunInputVector *) message->buffers, message->n_buffers, message->length,
4265 (agent->compatibility != NICE_COMPATIBILITY_OC2007 &&
4266 agent->compatibility != NICE_COMPATIBILITY_OC2007R2)) == (ssize_t) message->length) {
4267 /* Slow path: If this message isn’t obviously *not* a STUN packet, compact
4269 * into a single monolithic one and parse the packet properly. */
4274 big_buf = compact_input_message (message, &big_buf_len);
4276 validated_len = stun_message_validate_buffer_length (big_buf, big_buf_len,
4277 (agent->compatibility != NICE_COMPATIBILITY_OC2007 &&
4278 agent->compatibility != NICE_COMPATIBILITY_OC2007R2));
4280 if (validated_len == (gint) big_buf_len) {
4284 conn_check_handle_inbound_stun (agent, stream, component, nicesock,
4285 message->from, (gchar *) big_buf, big_buf_len);
4288 /* Handled STUN message. */
4289 nice_debug ("%s: Valid STUN packet received.", G_STRFUNC);
4292 agent->media_after_tick = TRUE;
4297 nice_debug ("%s: Packet passed fast STUN validation but failed "
4298 "slow validation.", G_STRFUNC);
4303 if (!nice_component_verify_remote_candidate (component,
4304 message->from, nicesock)) {
4305 if (nice_debug_is_verbose ()) {
4306 gchar str[INET6_ADDRSTRLEN];
4308 nice_address_to_string (message->from, str);
4309 nice_debug_verbose ("Agent %p : %d:%d DROPPING packet from unknown source"
4310 " %s:%d sock-type: %d", agent, stream->id, component->id, str,
4311 nice_address_get_port (message->from), nicesock->type);
4318 agent->media_after_tick = TRUE;
4320 /* Unhandled STUN; try handling TCP data, then pass to the client. */
4321 if (message->length > 0 && agent->reliable) {
4322 if (!nice_socket_is_reliable (nicesock) &&
4323 !pseudo_tcp_socket_is_closed (component->tcp)) {
4324 /* If we don’t yet have an underlying selected socket, queue up the
4325 * incoming data to handle later. This is because we can’t send ACKs (or,
4326 * more importantly for the first few packets, SYNACKs) without an
4327 * underlying socket. We’d rather wait a little longer for a pair to be
4328 * selected, then process the incoming packets and send out ACKs, than try
4329 * to process them now, fail to send the ACKs, and incur a timeout in our
4330 * pseudo-TCP state machine. */
4331 if (component->selected_pair.local == NULL) {
4332 GOutputVector *vec = g_slice_new (GOutputVector);
4333 vec->buffer = compact_input_message (message, &vec->size);
4334 g_queue_push_tail (&component->queued_tcp_packets, vec);
4335 nice_debug ("%s: Queued %" G_GSSIZE_FORMAT " bytes for agent %p.",
4336 G_STRFUNC, vec->size, agent);
4340 process_queued_tcp_packets (agent, stream, component);
4343 /* Received data on a reliable connection. */
4345 nice_debug_verbose ("%s: notifying pseudo-TCP of packet, length %" G_GSIZE_FORMAT,
4346 G_STRFUNC, message->length);
4347 pseudo_tcp_socket_notify_message (component->tcp, message);
4349 adjust_tcp_clock (agent, stream, component);
4351 /* Success! Handled out-of-band. */
4354 } else if (pseudo_tcp_socket_is_closed (component->tcp)) {
4355 nice_debug ("Received data on a pseudo tcp FAILED component. Ignoring.");
4363 /* Clear local modifications. */
4364 if (message->from == &from) {
4365 message->from = NULL;
4371 /* Print the composition of an array of messages. No-op if debugging is
4374 nice_debug_input_message_composition (const NiceInputMessage *messages,
4379 if (!nice_debug_is_verbose ())
4382 for (i = 0; i < n_messages; i++) {
4383 const NiceInputMessage *message = &messages[i];
4386 nice_debug_verbose ("Message %p (from: %p, length: %" G_GSIZE_FORMAT ")", message,
4387 message->from, message->length);
4390 (message->n_buffers >= 0 && j < (guint) message->n_buffers) ||
4391 (message->n_buffers < 0 && message->buffers[j].buffer != NULL);
4393 GInputVector *buffer = &message->buffers[j];
4395 nice_debug_verbose ("\tBuffer %p (length: %" G_GSIZE_FORMAT ")", buffer->buffer,
4402 compact_message (const NiceOutputMessage *message, gsize buffer_length)
4408 buffer = g_malloc (buffer_length);
4411 (message->n_buffers >= 0 && i < (guint) message->n_buffers) ||
4412 (message->n_buffers < 0 && message->buffers[i].buffer != NULL);
4414 gsize len = MIN (buffer_length - offset, message->buffers[i].size);
4415 memcpy (buffer + offset, message->buffers[i].buffer, len);
4422 /* Concatenate all the buffers in the given @recv_message into a single, newly
4423 * allocated, monolithic buffer which is returned. The length of the new buffer
4424 * is returned in @buffer_length, and should be equal to the length field of
4427 * The return value must be freed with g_free(). */
4429 compact_input_message (const NiceInputMessage *message, gsize *buffer_length)
4431 nice_debug_verbose ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
4432 nice_debug_input_message_composition (message, 1);
4434 /* This works as long as NiceInputMessage is a subset of eNiceOutputMessage */
4436 *buffer_length = message->length;
4438 return compact_message ((NiceOutputMessage *) message, *buffer_length);
4441 /* Returns the number of bytes copied. Silently drops any data from @buffer
4442 * which doesn’t fit in @message. */
4444 memcpy_buffer_to_input_message (NiceInputMessage *message,
4445 const guint8 *buffer, gsize buffer_length)
4449 nice_debug_verbose ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
4451 message->length = 0;
4454 buffer_length > 0 &&
4455 ((message->n_buffers >= 0 && i < (guint) message->n_buffers) ||
4456 (message->n_buffers < 0 && message->buffers[i].buffer != NULL));
4460 len = MIN (message->buffers[i].size, buffer_length);
4461 memcpy (message->buffers[i].buffer, buffer, len);
4464 buffer_length -= len;
4466 message->length += len;
4469 nice_debug_input_message_composition (message, 1);
4471 if (buffer_length > 0) {
4472 g_warning ("Dropped %" G_GSIZE_FORMAT " bytes of data from the end of "
4473 "buffer %p (length: %" G_GSIZE_FORMAT ") due to not fitting in "
4474 "message %p", buffer_length, buffer - message->length,
4475 message->length + buffer_length, message);
4478 return message->length;
4481 /* Concatenate all the buffers in the given @message into a single, newly
4482 * allocated, monolithic buffer which is returned. The length of the new buffer
4483 * is returned in @buffer_length, and should be equal to the length field of
4486 * The return value must be freed with g_free(). */
4488 compact_output_message (const NiceOutputMessage *message, gsize *buffer_length)
4490 nice_debug ("%s: **WARNING: SLOW PATH**", G_STRFUNC);
4492 *buffer_length = output_message_get_size (message);
4494 return compact_message (message, *buffer_length);
4498 output_message_get_size (const NiceOutputMessage *message)
4501 gsize message_len = 0;
4503 /* Find the total size of the message */
4505 (message->n_buffers >= 0 && i < (guint) message->n_buffers) ||
4506 (message->n_buffers < 0 && message->buffers[i].buffer != NULL);
4508 message_len += message->buffers[i].size;
4514 input_message_get_size (const NiceInputMessage *message)
4517 gsize message_len = 0;
4519 /* Find the total size of the message */
4521 (message->n_buffers >= 0 && i < (guint) message->n_buffers) ||
4522 (message->n_buffers < 0 && message->buffers[i].buffer != NULL);
4524 message_len += message->buffers[i].size;
4530 * nice_input_message_iter_reset:
4531 * @iter: a #NiceInputMessageIter
4533 * Reset the given @iter to point to the beginning of the array of messages.
4534 * This may be used both to initialise it and to reset it after use.
4539 nice_input_message_iter_reset (NiceInputMessageIter *iter)
4547 * nice_input_message_iter_is_at_end:
4548 * @iter: a #NiceInputMessageIter
4549 * @messages: (array length=n_messages): an array of #NiceInputMessages
4550 * @n_messages: number of entries in @messages
4552 * Determine whether @iter points to the end of the given @messages array. If it
4553 * does, the array is full: every buffer in every message is full of valid
4556 * Returns: %TRUE if the messages’ buffers are full, %FALSE otherwise
4561 nice_input_message_iter_is_at_end (NiceInputMessageIter *iter,
4562 NiceInputMessage *messages, guint n_messages)
4564 return (iter->message == n_messages &&
4565 iter->buffer == 0 && iter->offset == 0);
4569 * nice_input_message_iter_get_n_valid_messages:
4570 * @iter: a #NiceInputMessageIter
4572 * Calculate the number of valid messages in the messages array. A valid message
4573 * is one which contains at least one valid byte of data in its buffers.
4575 * Returns: number of valid messages (may be zero)
4580 nice_input_message_iter_get_n_valid_messages (NiceInputMessageIter *iter)
4582 if (iter->buffer == 0 && iter->offset == 0)
4583 return iter->message;
4585 return iter->message + 1;
4589 * nice_input_message_iter_compare:
4590 * @a: a #NiceInputMessageIter
4591 * @b: another #NiceInputMessageIter
4593 * Compare two #NiceInputMessageIters for equality, returning %TRUE if they
4594 * point to the same place in the receive message array.
4596 * Returns: %TRUE if the iters match, %FALSE otherwise
4601 nice_input_message_iter_compare (const NiceInputMessageIter *a,
4602 const NiceInputMessageIter *b)
4604 return (a->message == b->message && a->buffer == b->buffer && a->offset == b->offset);
4607 /* Will fill up @messages from the first free byte onwards (as determined using
4608 * @iter). This may be used in reliable or non-reliable mode; in non-reliable
4609 * mode it will always increment the message index after each buffer is
4612 * Updates @iter in place. No errors can occur.
4614 * Returns the number of valid messages in @messages on success (which may be
4615 * zero if reading into the first buffer of the message would have blocked).
4617 * Must be called with the io_mutex held. */
4619 pending_io_messages_recv_messages (NiceComponent *component, gboolean reliable,
4620 NiceInputMessage *messages, guint n_messages, NiceInputMessageIter *iter)
4623 IOCallbackData *data;
4624 NiceInputMessage *message = &messages[iter->message];
4626 g_assert_cmpuint (component->io_callback_id, ==, 0);
4628 data = g_queue_peek_head (&component->pending_io_messages);
4632 if (iter->buffer == 0 && iter->offset == 0) {
4633 message->length = 0;
4637 (message->n_buffers >= 0 && iter->buffer < (guint) message->n_buffers) ||
4638 (message->n_buffers < 0 && message->buffers[iter->buffer].buffer != NULL);
4640 GInputVector *buffer = &message->buffers[iter->buffer];
4643 len = MIN (data->buf_len - data->offset, buffer->size - iter->offset);
4644 memcpy ((guint8 *) buffer->buffer + iter->offset,
4645 data->buf + data->offset, len);
4647 nice_debug ("%s: Unbuffered %" G_GSIZE_FORMAT " bytes into "
4648 "buffer %p (offset %" G_GSIZE_FORMAT ", length %" G_GSIZE_FORMAT
4649 ").", G_STRFUNC, len, buffer->buffer, iter->offset, buffer->size);
4651 message->length += len;
4652 iter->offset += len;
4653 data->offset += len;
4654 } while (iter->offset < buffer->size);
4659 /* Only if we managed to consume the whole buffer should it be popped off the
4660 * queue; otherwise we’ll have another go at it later. */
4661 if (data->offset == data->buf_len) {
4662 g_queue_pop_head (&component->pending_io_messages);
4663 io_callback_data_free (data);
4665 /* If we’ve consumed an entire message from pending_io_messages, and
4666 * are in non-reliable mode, move on to the next message in
4676 return nice_input_message_iter_get_n_valid_messages (iter);
4680 nice_agent_recv_cancelled_cb (GCancellable *cancellable, gpointer user_data)
4682 GError **error = user_data;
4684 if (error && !*error)
4685 g_cancellable_set_error_if_cancelled (cancellable, error);
4686 return G_SOURCE_REMOVE;
4690 nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent,
4691 guint stream_id, guint component_id, gboolean blocking,
4692 NiceInputMessage *messages, guint n_messages,
4693 GCancellable *cancellable, GError **error)
4695 GMainContext *context;
4697 NiceComponent *component;
4698 gint n_valid_messages = -1;
4699 GSource *cancellable_source = NULL;
4700 gboolean received_enough = FALSE, error_reported = FALSE;
4701 gboolean all_sockets_would_block = FALSE;
4702 gboolean reached_eos = FALSE;
4703 GError *child_error = NULL;
4704 NiceInputMessage *messages_orig = NULL;
4707 g_return_val_if_fail (NICE_IS_AGENT (agent), -1);
4708 g_return_val_if_fail (stream_id >= 1, -1);
4709 g_return_val_if_fail (component_id >= 1, -1);
4710 g_return_val_if_fail (n_messages == 0 || messages != NULL, -1);
4711 g_return_val_if_fail (
4712 cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1);
4713 g_return_val_if_fail (error == NULL || *error == NULL, -1);
4715 if (n_messages == 0)
4718 if (n_messages > G_MAXINT) {
4719 g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
4720 "The number of messages can't exceed G_MAXINT: %d", G_MAXINT);
4724 /* Receive buffer size must be at least 1280 for STUN */
4725 if (!agent->reliable) {
4726 for (i = 0; i < n_messages; i++) {
4727 if (input_message_get_size (&messages[i]) < 1280) {
4730 if (messages_orig == NULL)
4731 messages_orig = g_memdup (messages,
4732 sizeof (NiceInputMessage) * n_messages);
4733 vec = g_slice_new (GInputVector);
4734 vec->buffer = g_slice_alloc (1280);
4736 messages[i].buffers = vec;
4737 messages[i].n_buffers = 1;
4744 if (!agent_find_component (agent, stream_id, component_id,
4745 &stream, &component)) {
4746 g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE,
4747 "Invalid stream/component.");
4751 nice_debug_verbose ("%s: %p: (%s):", G_STRFUNC, agent,
4752 blocking ? "blocking" : "non-blocking");
4753 nice_debug_input_message_composition (messages, n_messages);
4755 /* Disallow re-entrant reads. */
4756 g_assert (component->n_recv_messages == 0 &&
4757 component->recv_messages == NULL);
4759 /* Set the component’s receive buffer. */
4760 context = nice_component_dup_io_context (component);
4761 nice_component_set_io_callback (component, NULL, NULL, messages, n_messages,
4764 /* Add the cancellable as a source. */
4765 if (cancellable != NULL) {
4766 cancellable_source = g_cancellable_source_new (cancellable);
4767 g_source_set_callback (cancellable_source,
4768 (GSourceFunc) G_CALLBACK (nice_agent_recv_cancelled_cb), &child_error,
4770 g_source_attach (cancellable_source, context);
4773 /* Is there already pending data left over from having an I/O callback
4774 * attached and switching to using nice_agent_recv()? This is a horrifically
4775 * specific use case which I hope nobody ever tries. And yet, it still must be
4777 g_mutex_lock (&component->io_mutex);
4779 while (!received_enough &&
4780 !g_queue_is_empty (&component->pending_io_messages)) {
4781 pending_io_messages_recv_messages (component, agent->reliable,
4782 component->recv_messages, component->n_recv_messages,
4783 &component->recv_messages_iter);
4785 nice_debug_verbose ("%s: %p: Received %d valid messages from pending I/O buffer.",
4787 nice_input_message_iter_get_n_valid_messages (
4788 &component->recv_messages_iter));
4791 nice_input_message_iter_is_at_end (&component->recv_messages_iter,
4792 component->recv_messages, component->n_recv_messages);
4795 g_mutex_unlock (&component->io_mutex);
4797 /* For a reliable stream, grab any data from the pseudo-TCP input buffer
4798 * before trying the sockets. */
4799 if (agent->reliable &&
4800 pseudo_tcp_socket_get_available_bytes (component->tcp) > 0) {
4801 pseudo_tcp_socket_recv_messages (component->tcp,
4802 component->recv_messages, component->n_recv_messages,
4803 &component->recv_messages_iter, &child_error);
4804 adjust_tcp_clock (agent, stream, component);
4806 nice_debug_verbose ("%s: %p: Received %d valid messages from pseudo-TCP read "
4807 "buffer.", G_STRFUNC, agent,
4808 nice_input_message_iter_get_n_valid_messages (
4809 &component->recv_messages_iter));
4812 nice_input_message_iter_is_at_end (&component->recv_messages_iter,
4813 component->recv_messages, component->n_recv_messages);
4814 error_reported = (child_error != NULL);
4817 /* Each iteration of the main context will either receive some data, a
4818 * cancellation error or a socket error. In non-reliable mode, the iter’s
4819 * @message counter will be incremented after each read.
4821 * In blocking, reliable mode, iterate the loop enough to fill exactly
4822 * @n_messages messages. In blocking, non-reliable mode, iterate the loop to
4823 * receive @n_messages messages (which may not fill all the buffers). In
4824 * non-blocking mode, stop iterating the loop if all sockets would block (i.e.
4825 * if no data was received for an iteration; in which case @child_error will
4826 * be set to %G_IO_ERROR_WOULD_BLOCK).
4828 while (!received_enough && !error_reported && !all_sockets_would_block &&
4830 NiceInputMessageIter prev_recv_messages_iter;
4832 g_clear_error (&child_error);
4833 memcpy (&prev_recv_messages_iter, &component->recv_messages_iter,
4834 sizeof (NiceInputMessageIter));
4836 agent_unlock (agent);
4837 g_main_context_iteration (context, blocking);
4840 if (!agent_find_component (agent, stream_id, component_id,
4841 &stream, &component)) {
4842 g_clear_error (&child_error);
4843 g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE,
4844 "Component removed during call.");
4852 nice_input_message_iter_is_at_end (&component->recv_messages_iter,
4853 component->recv_messages, component->n_recv_messages);
4854 error_reported = (child_error != NULL &&
4855 !g_error_matches (child_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK));
4856 reached_eos = (agent->reliable &&
4857 pseudo_tcp_socket_is_closed_remotely (component->tcp) &&
4858 nice_input_message_iter_compare (&prev_recv_messages_iter,
4859 &component->recv_messages_iter));
4860 all_sockets_would_block = (!blocking && !reached_eos &&
4861 nice_input_message_iter_compare (&prev_recv_messages_iter,
4862 &component->recv_messages_iter));
4866 nice_input_message_iter_get_n_valid_messages (
4867 &component->recv_messages_iter); /* grab before resetting the iter */
4869 nice_component_set_io_callback (component, NULL, NULL, NULL, 0, NULL);
4872 /* Tidy up. Below this point, @component may be %NULL. */
4873 if (cancellable_source != NULL) {
4874 g_source_destroy (cancellable_source);
4875 g_source_unref (cancellable_source);
4878 g_main_context_unref (context);
4880 /* Handle errors and cancellations. */
4881 if (child_error != NULL) {
4882 n_valid_messages = -1;
4883 } else if (n_valid_messages == 0 && all_sockets_would_block) {
4884 g_set_error_literal (&child_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
4885 g_strerror (EAGAIN));
4886 n_valid_messages = -1;
4889 nice_debug_verbose ("%s: %p: n_valid_messages: %d, n_messages: %u", G_STRFUNC, agent,
4890 n_valid_messages, n_messages);
4893 g_assert ((child_error != NULL) == (n_valid_messages == -1));
4894 g_assert (n_valid_messages < 0 || (guint) n_valid_messages <= n_messages);
4895 g_assert (n_valid_messages != 0 || reached_eos);
4897 if (child_error != NULL)
4898 g_propagate_error (error, child_error);
4900 agent_unlock_and_emit (agent);
4902 if (messages_orig) {
4903 for (i = 0; i < n_messages; i++) {
4904 if (messages[i].buffers != messages_orig[i].buffers) {
4905 g_assert_cmpint (messages[i].n_buffers, ==, 1);
4907 memcpy_buffer_to_input_message (&messages_orig[i],
4908 messages[i].buffers[0].buffer, messages[i].length);
4910 g_slice_free1 (1280, messages[i].buffers[0].buffer);
4911 g_slice_free (GInputVector, messages[i].buffers);
4913 messages[i].buffers = messages_orig[i].buffers;
4914 messages[i].n_buffers = messages_orig[i].n_buffers;
4915 messages[i].length = messages_orig[i].length;
4918 g_free (messages_orig);
4921 return n_valid_messages;
4925 nice_agent_recv_messages (NiceAgent *agent, guint stream_id, guint component_id,
4926 NiceInputMessage *messages, guint n_messages, GCancellable *cancellable,
4929 return nice_agent_recv_messages_blocking_or_nonblocking (agent, stream_id,
4930 component_id, TRUE, messages, n_messages, cancellable, error);
4933 NICEAPI_EXPORT gssize
4934 nice_agent_recv (NiceAgent *agent, guint stream_id, guint component_id,
4935 guint8 *buf, gsize buf_len, GCancellable *cancellable, GError **error)
4937 gint n_valid_messages;
4938 GInputVector local_bufs = { buf, buf_len };
4939 NiceInputMessage local_messages = { &local_bufs, 1, NULL, 0 };
4941 g_return_val_if_fail (NICE_IS_AGENT (agent), -1);
4942 g_return_val_if_fail (stream_id >= 1, -1);
4943 g_return_val_if_fail (component_id >= 1, -1);
4944 g_return_val_if_fail (buf != NULL || buf_len == 0, -1);
4945 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1);
4946 g_return_val_if_fail (error == NULL || *error == NULL, -1);
4948 if (buf_len > G_MAXSSIZE) {
4949 g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
4950 "The buffer length can't exceed G_MAXSSIZE: %" G_GSSIZE_FORMAT,
4955 n_valid_messages = nice_agent_recv_messages (agent, stream_id, component_id,
4956 &local_messages, 1, cancellable, error);
4958 if (n_valid_messages <= 0)
4959 return n_valid_messages;
4961 return local_messages.length;
4965 nice_agent_recv_messages_nonblocking (NiceAgent *agent, guint stream_id,
4966 guint component_id, NiceInputMessage *messages, guint n_messages,
4967 GCancellable *cancellable, GError **error)
4969 return nice_agent_recv_messages_blocking_or_nonblocking (agent, stream_id,
4970 component_id, FALSE, messages, n_messages, cancellable, error);
4973 NICEAPI_EXPORT gssize
4974 nice_agent_recv_nonblocking (NiceAgent *agent, guint stream_id,
4975 guint component_id, guint8 *buf, gsize buf_len, GCancellable *cancellable,
4978 gint n_valid_messages;
4979 GInputVector local_bufs = { buf, buf_len };
4980 NiceInputMessage local_messages = { &local_bufs, 1, NULL, 0 };
4982 g_return_val_if_fail (NICE_IS_AGENT (agent), -1);
4983 g_return_val_if_fail (stream_id >= 1, -1);
4984 g_return_val_if_fail (component_id >= 1, -1);
4985 g_return_val_if_fail (buf != NULL || buf_len == 0, -1);
4986 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1);
4987 g_return_val_if_fail (error == NULL || *error == NULL, -1);
4989 if (buf_len > G_MAXSSIZE) {
4990 g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
4991 "The buffer length can't exceed G_MAXSSIZE: %" G_GSSIZE_FORMAT,
4996 n_valid_messages = nice_agent_recv_messages_nonblocking (agent, stream_id,
4997 component_id, &local_messages, 1, cancellable, error);
4999 if (n_valid_messages <= 0)
5000 return n_valid_messages;
5002 return local_messages.length;
5005 /* nice_agent_send_messages_nonblocking_internal:
5007 * Returns: number of bytes sent if allow_partial is %TRUE, the number
5008 * of messages otherwise.
5012 nice_agent_send_messages_nonblocking_internal (
5016 const NiceOutputMessage *messages,
5018 gboolean allow_partial,
5022 NiceComponent *component;
5023 gint n_sent = -1; /* is in bytes if allow_partial is TRUE,
5024 otherwise in messages */
5025 GError *child_error = NULL;
5027 g_assert (n_messages == 1 || !allow_partial);
5031 if (!agent_find_component (agent, stream_id, component_id,
5032 &stream, &component)) {
5033 g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE,
5034 "Invalid stream/component.");
5038 /* FIXME: Cancellation isn’t yet supported, but it doesn’t matter because
5039 * we only deal with non-blocking writes. */
5040 if (component->selected_pair.local != NULL) {
5041 if (nice_debug_is_enabled ()) {
5042 gchar tmpbuf[INET6_ADDRSTRLEN];
5043 nice_address_to_string (&component->selected_pair.remote->addr, tmpbuf);
5045 nice_debug_verbose ("Agent %p : s%d:%d: sending %u messages to "
5046 "[%s]:%d", agent, stream_id, component_id, n_messages, tmpbuf,
5047 nice_address_get_port (&component->selected_pair.remote->addr));
5050 if(agent->reliable &&
5051 !nice_socket_is_reliable (component->selected_pair.local->sockptr)) {
5052 if (!pseudo_tcp_socket_is_closed (component->tcp)) {
5053 /* Send on the pseudo-TCP socket. */
5054 n_sent = pseudo_tcp_socket_send_messages (component->tcp, messages,
5055 n_messages, allow_partial, &child_error);
5056 adjust_tcp_clock (agent, stream, component);
5058 if (!pseudo_tcp_socket_can_send (component->tcp))
5059 g_cancellable_reset (component->tcp_writable_cancellable);
5060 if (n_sent < 0 && !g_error_matches (child_error, G_IO_ERROR,
5061 G_IO_ERROR_WOULD_BLOCK)) {
5063 priv_pseudo_tcp_error (agent, component);
5066 g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_FAILED,
5067 "Pseudo-TCP socket not connected.");
5073 sock = component->selected_pair.local->sockptr;
5074 addr = &component->selected_pair.remote->addr;
5076 if (nice_socket_is_reliable (sock)) {
5079 /* ICE-TCP requires that all packets be framed with RFC4571 */
5081 for (i = 0; i < n_messages; i++) {
5082 const NiceOutputMessage *message = &messages[i];
5083 gsize message_len = output_message_get_size (message);
5085 gsize current_offset = 0;
5086 gsize offset_in_buffer = 0;
5088 GOutputVector *local_bufs;
5089 NiceOutputMessage local_message;
5093 /* Count the number of buffers. */
5094 if (message->n_buffers == -1) {
5095 for (j = 0; message->buffers[j].buffer != NULL; j++)
5098 n_bufs = message->n_buffers;
5101 local_bufs = g_malloc_n (n_bufs + 1, sizeof (GOutputVector));
5102 local_message.buffers = local_bufs;
5104 while (message_len > 0) {
5106 guint16 rfc4571_frame;
5108 /* Split long messages into 62KB packets, leaving enough space
5109 * for TURN overhead as well */
5110 if (message_len > 0xF800)
5111 packet_len = 0xF800;
5113 packet_len = (guint16) message_len;
5114 message_len -= packet_len;
5115 rfc4571_frame = htons (packet_len);
5117 local_bufs[0].buffer = &rfc4571_frame;
5118 local_bufs[0].size = sizeof (guint16);
5120 local_message.n_buffers = 1;
5121 /* If we had to split the message, we need to find which buffer
5122 * to start copying from and our offset within that buffer */
5123 offset_in_buffer = 0;
5125 for (j = 0; j < n_bufs; j++) {
5126 if (message->buffers[j].size < offset - current_offset) {
5127 current_offset += message->buffers[j].size;
5130 offset_in_buffer = offset - current_offset;
5131 current_offset = offset;
5136 /* Keep j position in array and start copying from there */
5137 for (; j < n_bufs; j++) {
5138 local_bufs[local_message.n_buffers].buffer =
5139 ((guint8 *) message->buffers[j].buffer) + offset_in_buffer;
5140 local_bufs[local_message.n_buffers].size =
5141 MIN (message->buffers[j].size, packet_len);
5142 packet_len -= local_bufs[local_message.n_buffers].size;
5143 offset += local_bufs[local_message.n_buffers++].size;
5144 offset_in_buffer = 0;
5147 /* If we sent part of the message already, then send the rest
5148 * reliably so the message is sent as a whole even if it's split */
5149 if (current_offset == 0)
5150 n_sent_framed = nice_socket_send_messages (sock, addr,
5153 n_sent_framed = nice_socket_send_messages_reliable (sock, addr,
5156 if (component->tcp_writable_cancellable &&
5157 !nice_socket_can_send (sock, addr))
5158 g_cancellable_reset (component->tcp_writable_cancellable);
5160 if (n_sent_framed < 0 && n_sent == 0)
5161 n_sent = n_sent_framed;
5162 if (n_sent_framed != 1)
5164 /* This is the last split frame, increment n_sent */
5165 if (message_len == 0)
5168 g_free (local_bufs);
5172 n_sent = nice_socket_send_messages (sock, addr, messages, n_messages);
5176 g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_FAILED,
5177 "Error writing data to socket.");
5178 } else if (n_sent > 0 && allow_partial) {
5179 g_assert_cmpuint (n_messages, ==, 1);
5180 n_sent = output_message_get_size (messages);
5184 /* Socket isn’t properly open yet. */
5185 n_sent = 0; /* EWOULDBLOCK */
5188 /* Handle errors and cancellations. */
5190 g_set_error_literal (&child_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
5191 g_strerror (EAGAIN));
5195 nice_debug_verbose ("%s: n_sent: %d, n_messages: %u", G_STRFUNC,
5196 n_sent, n_messages);
5199 g_assert ((child_error != NULL) == (n_sent == -1));
5200 g_assert_cmpint (n_sent, !=, 0);
5201 g_assert (n_sent < 0 ||
5202 (!allow_partial && (guint) n_sent <= n_messages) ||
5203 (allow_partial && n_messages == 1 &&
5204 (gsize) n_sent <= output_message_get_size (&messages[0])));
5206 if (child_error != NULL)
5207 g_propagate_error (error, child_error);
5209 agent_unlock_and_emit (agent);
5215 nice_agent_send_messages_nonblocking (
5219 const NiceOutputMessage *messages,
5221 GCancellable *cancellable,
5224 g_return_val_if_fail (NICE_IS_AGENT (agent), -1);
5225 g_return_val_if_fail (stream_id >= 1, -1);
5226 g_return_val_if_fail (component_id >= 1, -1);
5227 g_return_val_if_fail (n_messages == 0 || messages != NULL, -1);
5228 g_return_val_if_fail (
5229 cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1);
5230 g_return_val_if_fail (error == NULL || *error == NULL, -1);
5232 if (g_cancellable_set_error_if_cancelled (cancellable, error))
5235 return nice_agent_send_messages_nonblocking_internal (agent, stream_id,
5236 component_id, messages, n_messages, FALSE, error);
5247 GOutputVector local_buf = { buf, len };
5248 NiceOutputMessage local_message = { &local_buf, 1 };
5251 g_return_val_if_fail (NICE_IS_AGENT (agent), -1);
5252 g_return_val_if_fail (stream_id >= 1, -1);
5253 g_return_val_if_fail (component_id >= 1, -1);
5254 g_return_val_if_fail (buf != NULL, -1);
5256 n_sent_bytes = nice_agent_send_messages_nonblocking_internal (agent,
5257 stream_id, component_id, &local_message, 1, TRUE, NULL);
5259 return n_sent_bytes;
5262 NICEAPI_EXPORT GSList *
5263 nice_agent_get_local_candidates (
5268 NiceComponent *component;
5269 GSList * ret = NULL;
5270 GSList * item = NULL;
5272 g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
5273 g_return_val_if_fail (stream_id >= 1, NULL);
5274 g_return_val_if_fail (component_id >= 1, NULL);
5278 if (!agent_find_component (agent, stream_id, component_id, NULL, &component)) {
5282 for (item = component->local_candidates; item; item = item->next) {
5283 NiceCandidate *cand = item->data;
5285 if (agent->force_relay && cand->type != NICE_CANDIDATE_TYPE_RELAYED)
5288 ret = g_slist_append (ret, nice_candidate_copy (cand));
5292 agent_unlock_and_emit (agent);
5297 NICEAPI_EXPORT GSList *
5298 nice_agent_get_remote_candidates (
5303 NiceComponent *component;
5304 GSList *ret = NULL, *item = NULL;
5306 g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
5307 g_return_val_if_fail (stream_id >= 1, NULL);
5308 g_return_val_if_fail (component_id >= 1, NULL);
5311 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
5316 for (item = component->remote_candidates; item; item = item->next)
5317 ret = g_slist_append (ret, nice_candidate_copy (item->data));
5320 agent_unlock_and_emit (agent);
5325 nice_agent_restart (
5332 /* step: regenerate tie-breaker value */
5333 priv_generate_tie_breaker (agent);
5335 /* step: reset controlling mode from the property value */
5336 agent->controlling_mode = agent->saved_controlling_mode;
5337 nice_debug ("Agent %p : ICE restart, reset role to \"%s\".",
5338 agent, agent->controlling_mode ? "controlling" : "controlled");
5340 for (i = agent->streams; i; i = i->next) {
5341 NiceStream *stream = i->data;
5343 /* step: reset local credentials for the stream and
5344 * clean up the list of remote candidates */
5345 nice_stream_restart (stream, agent);
5348 agent_unlock_and_emit (agent);
5353 nice_agent_restart_stream (
5357 gboolean res = FALSE;
5362 stream = agent_find_stream (agent, stream_id);
5364 g_warning ("Could not find stream %u", stream_id);
5368 /* step: reset local credentials for the stream and
5369 * clean up the list of remote candidates */
5370 nice_stream_restart (stream, agent);
5374 agent_unlock_and_emit (agent);
5380 nice_agent_dispose (GObject *object)
5384 NiceAgent *agent = NICE_AGENT (object);
5388 /* step: free resources for the binding discovery timers */
5389 discovery_free (agent);
5390 g_assert (agent->discovery_list == NULL);
5392 /* step: free resources for the connectivity check timers */
5393 conn_check_free (agent);
5395 priv_remove_keepalive_timer (agent);
5397 for (i = agent->local_addresses; i; i = i->next)
5399 NiceAddress *a = i->data;
5401 nice_address_free (a);
5404 g_slist_free (agent->local_addresses);
5405 agent->local_addresses = NULL;
5407 while (agent->streams) {
5408 NiceStream *s = agent->streams->data;
5410 nice_stream_close (agent, s);
5413 agent->streams = g_slist_delete_link(agent->streams, agent->streams);
5416 while (agent->pruning_streams) {
5417 NiceStream *s = agent->pruning_streams->data;
5419 nice_stream_close (agent, s);
5422 agent->pruning_streams = g_slist_delete_link(agent->pruning_streams,
5423 agent->pruning_streams);
5426 while ((sig = g_queue_pop_head (&agent->pending_signals))) {
5427 free_queued_signal (sig);
5430 g_free (agent->stun_server_ip);
5431 agent->stun_server_ip = NULL;
5433 g_free (agent->proxy_ip);
5434 agent->proxy_ip = NULL;
5435 g_free (agent->proxy_username);
5436 agent->proxy_username = NULL;
5437 g_free (agent->proxy_password);
5438 agent->proxy_password = NULL;
5440 nice_rng_free (agent->rng);
5443 priv_stop_upnp (agent);
5447 g_object_unref (agent->upnp);
5452 g_free (agent->software_attribute);
5453 agent->software_attribute = NULL;
5455 if (agent->main_context != NULL)
5456 g_main_context_unref (agent->main_context);
5457 agent->main_context = NULL;
5459 agent_unlock (agent);
5461 g_mutex_clear (&agent->agent_mutex);
5463 if (G_OBJECT_CLASS (nice_agent_parent_class)->dispose)
5464 G_OBJECT_CLASS (nice_agent_parent_class)->dispose (object);
5469 component_io_cb (GSocket *gsocket, GIOCondition condition, gpointer user_data)
5471 SocketSource *socket_source = user_data;
5472 NiceComponent *component;
5475 gboolean has_io_callback;
5476 gboolean remove_source = FALSE;
5478 component = socket_source->component;
5480 agent = g_weak_ref_get (&component->agent_ref);
5482 return G_SOURCE_REMOVE;
5486 stream = agent_find_stream (agent, component->stream_id);
5488 if (stream == NULL) {
5489 nice_debug ("%s: stream %d destroyed", G_STRFUNC, component->stream_id);
5491 agent_unlock (agent);
5492 g_object_unref (agent);
5493 return G_SOURCE_REMOVE;
5496 if (g_source_is_destroyed (g_main_current_source ())) {
5497 /* Silently return FALSE. */
5498 nice_debug ("%s: source %p destroyed", G_STRFUNC, g_main_current_source ());
5500 agent_unlock (agent);
5501 g_object_unref (agent);
5502 return G_SOURCE_REMOVE;
5505 /* Remove disconnected sockets when we get a HUP */
5506 if (condition & G_IO_HUP) {
5507 nice_debug ("Agent %p: NiceSocket %p has received HUP", agent,
5508 socket_source->socket);
5509 if (component->selected_pair.local &&
5510 component->selected_pair.local->sockptr == socket_source->socket &&
5511 component->state == NICE_COMPONENT_STATE_READY) {
5512 nice_debug ("Agent %p: Selected pair socket %p has HUP, declaring failed",
5513 agent, socket_source->socket);
5514 agent_signal_component_state_change (agent,
5515 stream->id, component->id, NICE_COMPONENT_STATE_FAILED);
5518 nice_component_remove_socket (agent, component, socket_source->socket);
5519 agent_unlock (agent);
5520 g_object_unref (agent);
5521 return G_SOURCE_REMOVE;
5524 has_io_callback = nice_component_has_io_callback (component);
5526 /* Choose which receive buffer to use. If we’re reading for
5527 * nice_agent_attach_recv(), use a local static buffer. If we’re reading for
5528 * nice_agent_recv_messages(), use the buffer provided by the client.
5530 * has_io_callback cannot change throughout this function, as we operate
5531 * entirely with the agent lock held, and nice_component_set_io_callback()
5532 * would need to take the agent lock to change the Component’s
5534 g_assert (!has_io_callback || component->recv_messages == NULL);
5536 if (agent->reliable && !nice_socket_is_reliable (socket_source->socket)) {
5537 #define TCP_HEADER_SIZE 24 /* bytes */
5538 guint8 local_header_buf[TCP_HEADER_SIZE];
5539 /* FIXME: Currently, the critical path for reliable packet delivery has two
5540 * memcpy()s: one into the pseudo-TCP receive buffer, and one out of it.
5541 * This could moderately easily be reduced to one memcpy() in the common
5542 * case of in-order packet delivery, by replacing local_body_buf with a
5543 * pointer into the pseudo-TCP receive buffer. If it turns out the packet
5544 * is out-of-order (which we can only know after parsing its header), the
5545 * data will need to be moved in the buffer. If the packet *is* in order,
5546 * however, the only memcpy() then needed is from the pseudo-TCP receive
5547 * buffer to the client’s message buffers.
5549 * In fact, in the case of a reliable agent with I/O callbacks, zero
5550 * memcpy()s can be achieved (for in-order packet delivery) by emittin the
5551 * I/O callback directly from the pseudo-TCP receive buffer. */
5552 guint8 local_body_buf[MAX_BUFFER_SIZE];
5553 GInputVector local_bufs[] = {
5554 { local_header_buf, sizeof (local_header_buf) },
5555 { local_body_buf, sizeof (local_body_buf) },
5557 NiceInputMessage local_message = {
5558 local_bufs, G_N_ELEMENTS (local_bufs), NULL, 0
5560 RecvStatus retval = 0;
5562 if (pseudo_tcp_socket_is_closed (component->tcp)) {
5563 nice_debug ("Agent %p: not handling incoming packet for s%d:%d "
5564 "because pseudo-TCP socket does not exist in reliable mode.", agent,
5565 stream->id, component->id);
5566 remove_source = TRUE;
5570 while (has_io_callback ||
5571 (component->recv_messages != NULL &&
5572 !nice_input_message_iter_is_at_end (&component->recv_messages_iter,
5573 component->recv_messages, component->n_recv_messages))) {
5574 /* Receive a single message. This will receive it into the given
5575 * @local_bufs then, for pseudo-TCP, emit I/O callbacks or copy it into
5576 * component->recv_messages in pseudo_tcp_socket_readable(). STUN packets
5577 * will be parsed in-place. */
5578 retval = agent_recv_message_unlocked (agent, stream, component,
5579 socket_source->socket, &local_message);
5581 nice_debug_verbose ("%s: %p: received %d valid messages with %" G_GSSIZE_FORMAT
5582 " bytes", G_STRFUNC, agent, retval, local_message.length);
5584 /* Don’t expect any valid messages to escape pseudo_tcp_socket_readable()
5585 * when in reliable mode. */
5586 g_assert_cmpint (retval, !=, RECV_SUCCESS);
5588 if (retval == RECV_WOULD_BLOCK) {
5591 } else if (retval == RECV_ERROR) {
5593 nice_debug ("%s: error receiving message", G_STRFUNC);
5594 remove_source = TRUE;
5598 has_io_callback = nice_component_has_io_callback (component);
5600 } else if (has_io_callback) {
5601 while (has_io_callback) {
5602 guint8 local_buf[MAX_BUFFER_SIZE];
5603 GInputVector local_bufs = { local_buf, sizeof (local_buf) };
5604 NiceInputMessage local_message = { &local_bufs, 1, NULL, 0 };
5607 /* Receive a single message. */
5608 retval = agent_recv_message_unlocked (agent, stream, component,
5609 socket_source->socket, &local_message);
5611 if (retval == RECV_WOULD_BLOCK) {
5613 nice_debug_verbose ("%s: %p: no message available on read attempt",
5616 } else if (retval == RECV_ERROR) {
5618 nice_debug ("%s: %p: error receiving message", G_STRFUNC, agent);
5619 remove_source = TRUE;
5623 if (retval == RECV_SUCCESS) {
5624 nice_debug_verbose ("%s: %p: received a valid message with %" G_GSSIZE_FORMAT
5625 " bytes", G_STRFUNC, agent, local_message.length);
5627 if (local_message.length > 0) {
5628 nice_component_emit_io_callback (agent, component, local_buf,
5629 local_message.length);
5633 if (g_source_is_destroyed (g_main_current_source ())) {
5634 nice_debug ("Component IO source disappeared during the callback");
5637 has_io_callback = nice_component_has_io_callback (component);
5639 } else if (component->recv_messages != NULL) {
5642 /* Don’t want to trample over partially-valid buffers. */
5643 g_assert_cmpuint (component->recv_messages_iter.buffer, ==, 0);
5644 g_assert_cmpint (component->recv_messages_iter.offset, ==, 0);
5646 while (!nice_input_message_iter_is_at_end (&component->recv_messages_iter,
5647 component->recv_messages, component->n_recv_messages)) {
5648 /* Receive a single message. This will receive it into the given
5649 * user-provided #NiceInputMessage, which it’s the user’s responsibility
5650 * to ensure is big enough to avoid data loss (since we’re in non-reliable
5651 * mode). Iterate to receive as many messages as possible.
5653 * STUN packets will be parsed in-place. */
5654 retval = agent_recv_message_unlocked (agent, stream, component,
5655 socket_source->socket,
5656 &component->recv_messages[component->recv_messages_iter.message]);
5658 nice_debug_verbose ("%s: %p: received %d valid messages", G_STRFUNC, agent,
5661 if (retval == RECV_SUCCESS) {
5662 /* Successfully received a single message. */
5663 component->recv_messages_iter.message++;
5664 g_clear_error (component->recv_buf_error);
5665 } else if (retval == RECV_WOULD_BLOCK) {
5667 if (component->recv_messages_iter.message == 0 &&
5668 component->recv_buf_error != NULL &&
5669 *component->recv_buf_error == NULL) {
5670 g_set_error_literal (component->recv_buf_error, G_IO_ERROR,
5671 G_IO_ERROR_WOULD_BLOCK, g_strerror (EAGAIN));
5674 } else if (retval == RECV_ERROR) {
5676 remove_source = TRUE;
5678 } /* else if (retval == RECV_OOB) { ignore me and continue; } */
5685 nice_component_remove_socket (agent, component, socket_source->socket);
5687 /* If we’re in the middle of a read, don’t emit any signals, or we could cause
5688 * re-entrancy by (e.g.) emitting component-state-changed and having the
5689 * client perform a read. */
5690 if (component->n_recv_messages == 0 && component->recv_messages == NULL) {
5691 agent_unlock_and_emit (agent);
5693 agent_unlock (agent);
5696 g_object_unref (agent);
5698 return !remove_source;
5701 agent_unlock_and_emit (agent);
5703 g_object_unref (agent);
5705 return G_SOURCE_REMOVE;
5708 NICEAPI_EXPORT gboolean
5709 nice_agent_attach_recv (
5714 NiceAgentRecvFunc func,
5717 NiceComponent *component = NULL;
5718 NiceStream *stream = NULL;
5719 gboolean ret = FALSE;
5721 g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
5722 g_return_val_if_fail (stream_id >= 1, FALSE);
5723 g_return_val_if_fail (component_id >= 1, FALSE);
5727 /* attach candidates */
5729 /* step: check that params specify an existing pair */
5730 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
5731 g_warning ("Could not find component %u in stream %u", component_id,
5737 ctx = g_main_context_default ();
5739 /* Set the component’s I/O context. */
5740 nice_component_set_io_context (component, ctx);
5741 nice_component_set_io_callback (component, func, data, NULL, 0, NULL);
5745 /* If we got detached, maybe our readable callback didn't finish reading
5746 * all available data in the pseudotcp, so we need to make sure we free
5747 * our recv window, so the readable callback can be triggered again on the
5748 * next incoming data.
5749 * but only do this if we know we're already readable, otherwise we might
5750 * trigger an error in the initial, pre-connection attach. */
5751 if (agent->reliable && !pseudo_tcp_socket_is_closed (component->tcp) &&
5752 component->tcp_readable)
5753 pseudo_tcp_socket_readable (component->tcp, component);
5757 agent_unlock_and_emit (agent);
5761 NICEAPI_EXPORT gboolean
5762 nice_agent_set_selected_pair (
5766 const gchar *lfoundation,
5767 const gchar *rfoundation)
5769 NiceComponent *component;
5772 gboolean ret = FALSE;
5774 g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
5775 g_return_val_if_fail (stream_id >= 1, FALSE);
5776 g_return_val_if_fail (component_id >= 1, FALSE);
5777 g_return_val_if_fail (lfoundation, FALSE);
5778 g_return_val_if_fail (rfoundation, FALSE);
5782 /* step: check that params specify an existing pair */
5783 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
5787 if (!nice_component_find_pair (component, agent, lfoundation, rfoundation, &pair)){
5791 /* step: stop connectivity checks (note: for the whole stream) */
5792 conn_check_prune_stream (agent, stream);
5794 if (agent->reliable && !nice_socket_is_reliable (pair.local->sockptr) &&
5795 pseudo_tcp_socket_is_closed (component->tcp)) {
5796 nice_debug ("Agent %p: not setting selected pair for s%d:%d because "
5797 "pseudo tcp socket does not exist in reliable mode", agent,
5798 stream->id, component->id);
5802 /* step: change component state; we could be in STATE_DISCONNECTED; skip
5803 * STATE_GATHERING and continue through the states to give client code a nice
5804 * logical progression. See http://phabricator.freedesktop.org/D218 for
5806 if (component->state < NICE_COMPONENT_STATE_CONNECTING ||
5807 component->state == NICE_COMPONENT_STATE_FAILED)
5808 agent_signal_component_state_change (agent, stream_id, component_id,
5809 NICE_COMPONENT_STATE_CONNECTING);
5810 if (component->state < NICE_COMPONENT_STATE_CONNECTED)
5811 agent_signal_component_state_change (agent, stream_id, component_id,
5812 NICE_COMPONENT_STATE_CONNECTED);
5813 agent_signal_component_state_change (agent, stream_id, component_id,
5814 NICE_COMPONENT_STATE_READY);
5816 /* step: set the selected pair */
5817 nice_component_update_selected_pair (agent, component, &pair);
5818 agent_signal_new_selected_pair (agent, stream_id, component_id,
5819 pair.local, pair.remote);
5824 agent_unlock_and_emit (agent);
5828 NICEAPI_EXPORT gboolean
5829 nice_agent_get_selected_pair (NiceAgent *agent, guint stream_id,
5830 guint component_id, NiceCandidate **local, NiceCandidate **remote)
5832 NiceComponent *component;
5834 gboolean ret = FALSE;
5836 g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
5837 g_return_val_if_fail (stream_id >= 1, FALSE);
5838 g_return_val_if_fail (component_id >= 1, FALSE);
5839 g_return_val_if_fail (local != NULL, FALSE);
5840 g_return_val_if_fail (remote != NULL, FALSE);
5844 /* step: check that params specify an existing pair */
5845 if (!agent_find_component (agent, stream_id, component_id,
5846 &stream, &component))
5849 if (component->selected_pair.local && component->selected_pair.remote) {
5850 *local = component->selected_pair.local;
5851 *remote = component->selected_pair.remote;
5856 agent_unlock_and_emit (agent);
5861 NICEAPI_EXPORT GSocket *
5862 nice_agent_get_selected_socket (NiceAgent *agent, guint stream_id,
5865 NiceComponent *component;
5867 NiceSocket *nice_socket;
5868 GSocket *g_socket = NULL;
5870 g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
5871 g_return_val_if_fail (stream_id >= 1, NULL);
5872 g_return_val_if_fail (component_id >= 1, NULL);
5876 /* Reliable streams are pseudotcp or MUST use RFC 4571 framing */
5877 if (agent->reliable)
5880 /* step: check that params specify an existing pair */
5881 if (!agent_find_component (agent, stream_id, component_id,
5882 &stream, &component))
5885 if (!component->selected_pair.local || !component->selected_pair.remote)
5888 if (component->selected_pair.local->type == NICE_CANDIDATE_TYPE_RELAYED)
5891 /* ICE-TCP requires RFC4571 framing, even if unreliable */
5892 if (component->selected_pair.local->transport != NICE_CANDIDATE_TRANSPORT_UDP)
5895 nice_socket = (NiceSocket *)component->selected_pair.local->sockptr;
5896 if (nice_socket->fileno)
5897 g_socket = g_object_ref (nice_socket->fileno);
5900 agent_unlock_and_emit (agent);
5905 typedef struct _TimeoutData
5907 GWeakRef/*<NiceAgent>*/ agent_ref;
5908 NiceTimeoutLockedCallback function;
5913 timeout_data_destroy (TimeoutData *data)
5915 g_weak_ref_clear (&data->agent_ref);
5916 g_slice_free (TimeoutData, data);
5919 static TimeoutData *
5920 timeout_data_new (NiceAgent *agent, NiceTimeoutLockedCallback function,
5923 TimeoutData *data = g_slice_new0 (TimeoutData);
5925 g_weak_ref_init (&data->agent_ref, agent);
5926 data->function = function;
5927 data->user_data = user_data;
5933 timeout_cb (gpointer user_data)
5935 TimeoutData *data = user_data;
5937 gboolean ret = G_SOURCE_REMOVE;
5939 agent = g_weak_ref_get (&data->agent_ref);
5940 if (agent == NULL) {
5941 return G_SOURCE_REMOVE;
5946 /* A race condition might happen where the mutex above waits for the lock
5947 * and in the meantime another thread destroys the source.
5948 * In that case, we don't need to run the function since it should
5949 * have been cancelled */
5950 if (g_source_is_destroyed (g_main_current_source ())) {
5951 nice_debug ("Source was destroyed. Avoided race condition in timeout_cb");
5953 agent_unlock (agent);
5957 ret = data->function (agent, data->user_data);
5959 agent_unlock_and_emit (agent);
5962 g_object_unref (agent);
5967 /* Create a new timer GSource with the given @name, @interval, callback
5968 * @function and @data, and assign it to @out, destroying and freeing any
5969 * existing #GSource in @out first.
5971 * This guarantees that a timer won’t be overwritten without being destroyed.
5973 * @interval is given in milliseconds.
5975 static void agent_timeout_add_with_context_internal (NiceAgent *agent,
5976 GSource **out, const gchar *name, guint interval, gboolean seconds,
5977 NiceTimeoutLockedCallback function, gpointer user_data)
5982 g_return_if_fail (function != NULL);
5983 g_return_if_fail (out != NULL);
5985 /* Destroy any existing source. */
5987 g_source_destroy (*out);
5988 g_source_unref (*out);
5992 /* Create the new source. */
5994 source = g_timeout_source_new_seconds (interval);
5996 source = g_timeout_source_new (interval);
5998 g_source_set_name (source, name);
5999 data = timeout_data_new (agent, function, user_data);
6000 g_source_set_callback (source, timeout_cb, data,
6001 (GDestroyNotify)timeout_data_destroy);
6002 g_source_attach (source, agent->main_context);
6008 void agent_timeout_add_with_context (NiceAgent *agent,
6009 GSource **out, const gchar *name, guint interval,
6010 NiceTimeoutLockedCallback function, gpointer user_data)
6012 agent_timeout_add_with_context_internal (agent, out, name, interval, FALSE,
6013 function, user_data);
6016 void agent_timeout_add_seconds_with_context (NiceAgent *agent,
6017 GSource **out, const gchar *name, guint interval,
6018 NiceTimeoutLockedCallback function, gpointer user_data)
6020 agent_timeout_add_with_context_internal (agent, out, name, interval, TRUE,
6021 function, user_data);
6024 NICEAPI_EXPORT gboolean
6025 nice_agent_set_selected_remote_candidate (
6029 NiceCandidate *candidate)
6031 NiceComponent *component;
6033 NiceCandidate *lcandidate = NULL;
6034 gboolean ret = FALSE;
6035 NiceCandidate *local = NULL, *remote = NULL;
6038 g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
6039 g_return_val_if_fail (stream_id != 0, FALSE);
6040 g_return_val_if_fail (component_id != 0, FALSE);
6041 g_return_val_if_fail (candidate != NULL, FALSE);
6045 /* step: check if the component exists*/
6046 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
6050 /* step: stop connectivity checks (note: for the whole stream) */
6051 conn_check_prune_stream (agent, stream);
6053 /* Store previous selected pair */
6054 local = component->selected_pair.local;
6055 remote = component->selected_pair.remote;
6056 priority = component->selected_pair.priority;
6058 /* step: set the selected pair */
6059 lcandidate = nice_component_set_selected_remote_candidate (component, agent,
6064 if (agent->reliable && !nice_socket_is_reliable (lcandidate->sockptr) &&
6065 pseudo_tcp_socket_is_closed (component->tcp)) {
6066 nice_debug ("Agent %p: not setting selected remote candidate s%d:%d because"
6067 " pseudo tcp socket does not exist in reliable mode", agent,
6068 stream->id, component->id);
6069 /* Revert back to previous selected pair */
6070 /* FIXME: by doing this, we lose the keepalive tick */
6071 component->selected_pair.local = local;
6072 component->selected_pair.remote = remote;
6073 component->selected_pair.priority = priority;
6077 /* step: change component state; we could be in STATE_DISCONNECTED; skip
6078 * STATE_GATHERING and continue through the states to give client code a nice
6079 * logical progression. See http://phabricator.freedesktop.org/D218 for
6081 if (component->state < NICE_COMPONENT_STATE_CONNECTING ||
6082 component->state == NICE_COMPONENT_STATE_FAILED)
6083 agent_signal_component_state_change (agent, stream_id, component_id,
6084 NICE_COMPONENT_STATE_CONNECTING);
6085 if (component->state < NICE_COMPONENT_STATE_CONNECTED)
6086 agent_signal_component_state_change (agent, stream_id, component_id,
6087 NICE_COMPONENT_STATE_CONNECTED);
6088 agent_signal_component_state_change (agent, stream_id, component_id,
6089 NICE_COMPONENT_STATE_READY);
6091 agent_signal_new_selected_pair (agent, stream_id, component_id,
6092 lcandidate, candidate);
6097 agent_unlock_and_emit (agent);
6102 _priv_set_socket_tos (NiceAgent *agent, NiceSocket *sock, gint tos)
6104 if (sock->fileno == NULL)
6107 if (setsockopt (g_socket_get_fd (sock->fileno), IPPROTO_IP,
6108 IP_TOS, (const char *) &tos, sizeof (tos)) < 0) {
6109 nice_debug ("Agent %p: Could not set socket ToS: %s", agent,
6110 g_strerror (errno));
6113 if (setsockopt (g_socket_get_fd (sock->fileno), IPPROTO_IPV6,
6114 IPV6_TCLASS, (const char *) &tos, sizeof (tos)) < 0) {
6115 nice_debug ("Agent %p: Could not set IPV6 socket ToS: %s", agent,
6116 g_strerror (errno));
6123 nice_agent_set_stream_tos (NiceAgent *agent,
6124 guint stream_id, gint tos)
6129 g_return_if_fail (NICE_IS_AGENT (agent));
6130 g_return_if_fail (stream_id >= 1);
6134 stream = agent_find_stream (agent, stream_id);
6139 for (i = stream->components; i; i = i->next) {
6140 NiceComponent *component = i->data;
6142 for (j = component->local_candidates; j; j = j->next) {
6143 NiceCandidate *local_candidate = j->data;
6145 _priv_set_socket_tos (agent, local_candidate->sockptr, tos);
6150 agent_unlock_and_emit (agent);
6154 nice_agent_set_software (NiceAgent *agent, const gchar *software)
6156 g_return_if_fail (NICE_IS_AGENT (agent));
6160 g_free (agent->software_attribute);
6162 agent->software_attribute = g_strdup_printf ("%s/%s",
6163 software, PACKAGE_STRING);
6165 agent->software_attribute = NULL;
6167 nice_agent_reset_all_stun_agents (agent, TRUE);
6169 agent_unlock_and_emit (agent);
6172 NICEAPI_EXPORT gboolean
6173 nice_agent_set_stream_name (NiceAgent *agent, guint stream_id,
6176 NiceStream *stream_to_name = NULL;
6178 gboolean ret = FALSE;
6180 g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
6181 g_return_val_if_fail (stream_id >= 1, FALSE);
6182 g_return_val_if_fail (name, FALSE);
6184 if (strcmp (name, "audio") &&
6185 strcmp (name, "video") &&
6186 strcmp (name, "text") &&
6187 strcmp (name, "application") &&
6188 strcmp (name, "message") &&
6189 strcmp (name, "image")) {
6190 g_critical ("Stream name %s will produce invalid SDP, only \"audio\","
6191 " \"video\", \"text\", \"application\", \"image\" and \"message\""
6192 " are valid", name);
6197 for (i = agent->streams; i; i = i->next) {
6198 NiceStream *stream = i->data;
6200 if (stream->id != stream_id &&
6201 g_strcmp0 (stream->name, name) == 0)
6203 else if (stream->id == stream_id)
6204 stream_to_name = stream;
6207 if (stream_to_name == NULL)
6210 if (stream_to_name->name)
6211 g_free (stream_to_name->name);
6212 stream_to_name->name = g_strdup (name);
6216 agent_unlock_and_emit (agent);
6221 NICEAPI_EXPORT const gchar *
6222 nice_agent_get_stream_name (NiceAgent *agent, guint stream_id)
6227 g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
6228 g_return_val_if_fail (stream_id >= 1, NULL);
6232 stream = agent_find_stream (agent, stream_id);
6236 name = stream->name;
6239 agent_unlock_and_emit (agent);
6243 static NiceCandidate *
6244 _get_default_local_candidate_locked (NiceAgent *agent,
6245 NiceStream *stream, NiceComponent *component)
6248 NiceCandidate *default_candidate = NULL;
6249 NiceCandidate *default_rtp_candidate = NULL;
6251 if (component->id != NICE_COMPONENT_TYPE_RTP) {
6252 NiceComponent *rtp_component;
6254 if (!agent_find_component (agent, stream->id, NICE_COMPONENT_TYPE_RTP,
6255 NULL, &rtp_component))
6258 default_rtp_candidate = _get_default_local_candidate_locked (agent, stream,
6260 if (default_rtp_candidate == NULL)
6265 for (i = component->local_candidates; i; i = i->next) {
6266 NiceCandidate *local_candidate = i->data;
6268 if (agent->force_relay &&
6269 local_candidate->type != NICE_CANDIDATE_TYPE_RELAYED)
6272 /* Only check for ipv4 candidates */
6273 if (nice_address_ip_version (&local_candidate->addr) != 4)
6275 if (component->id == NICE_COMPONENT_TYPE_RTP) {
6276 if (default_candidate == NULL ||
6277 local_candidate->priority < default_candidate->priority) {
6278 default_candidate = local_candidate;
6280 } else if (strncmp (local_candidate->foundation,
6281 default_rtp_candidate->foundation,
6282 NICE_CANDIDATE_MAX_FOUNDATION) == 0) {
6283 default_candidate = local_candidate;
6289 return default_candidate;
6292 NICEAPI_EXPORT NiceCandidate *
6293 nice_agent_get_default_local_candidate (NiceAgent *agent,
6294 guint stream_id, guint component_id)
6296 NiceStream *stream = NULL;
6297 NiceComponent *component = NULL;
6298 NiceCandidate *default_candidate = NULL;
6300 g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
6301 g_return_val_if_fail (stream_id >= 1, NULL);
6302 g_return_val_if_fail (component_id >= 1, NULL);
6306 /* step: check if the component exists*/
6307 if (!agent_find_component (agent, stream_id, component_id,
6308 &stream, &component))
6311 default_candidate = _get_default_local_candidate_locked (agent, stream,
6313 if (default_candidate)
6314 default_candidate = nice_candidate_copy (default_candidate);
6317 agent_unlock_and_emit (agent);
6319 return default_candidate;
6322 static const gchar *
6323 _cand_type_to_sdp (NiceCandidateType type) {
6325 case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
6327 case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
6329 case NICE_CANDIDATE_TYPE_RELAYED:
6331 case NICE_CANDIDATE_TYPE_HOST:
6337 static const gchar *
6338 _transport_to_sdp (NiceCandidateTransport type) {
6340 case NICE_CANDIDATE_TRANSPORT_UDP:
6342 case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
6343 case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
6344 case NICE_CANDIDATE_TRANSPORT_TCP_SO:
6351 static const gchar *
6352 _transport_to_sdp_tcptype (NiceCandidateTransport type) {
6354 case NICE_CANDIDATE_TRANSPORT_UDP:
6356 case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
6358 case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
6360 case NICE_CANDIDATE_TRANSPORT_TCP_SO:
6368 _generate_candidate_sdp (NiceAgent *agent,
6369 NiceCandidate *candidate, GString *sdp)
6371 gchar ip4[INET6_ADDRSTRLEN];
6374 nice_address_to_string (&candidate->addr, ip4);
6375 port = nice_address_get_port (&candidate->addr);
6376 g_string_append_printf (sdp, "a=candidate:%.*s %d %s %d %s %d",
6377 NICE_CANDIDATE_MAX_FOUNDATION, candidate->foundation,
6378 candidate->component_id,
6379 _transport_to_sdp (candidate->transport),
6380 candidate->priority, ip4, port == 0 ? 9 : port);
6381 g_string_append_printf (sdp, " typ %s", _cand_type_to_sdp (candidate->type));
6382 if (nice_address_is_valid (&candidate->base_addr) &&
6383 !nice_address_equal (&candidate->addr, &candidate->base_addr)) {
6384 port = nice_address_get_port (&candidate->base_addr);
6385 nice_address_to_string (&candidate->base_addr, ip4);
6386 g_string_append_printf (sdp, " raddr %s rport %d", ip4,
6387 port == 0 ? 9 : port);
6389 if (candidate->transport != NICE_CANDIDATE_TRANSPORT_UDP) {
6390 g_string_append_printf (sdp, " tcptype %s",
6391 _transport_to_sdp_tcptype (candidate->transport));
6396 _generate_stream_sdp (NiceAgent *agent, NiceStream *stream,
6397 GString *sdp, gboolean include_non_ice)
6401 if (include_non_ice) {
6402 NiceAddress rtp, rtcp;
6403 gchar ip4[INET6_ADDRSTRLEN] = "";
6405 nice_address_init (&rtp);
6406 nice_address_set_ipv4 (&rtp, 0);
6407 nice_address_init (&rtcp);
6408 nice_address_set_ipv4 (&rtcp, 0);
6410 /* Find default candidates */
6411 for (i = stream->components; i; i = i->next) {
6412 NiceComponent *component = i->data;
6413 NiceCandidate *default_candidate;
6415 if (component->id == NICE_COMPONENT_TYPE_RTP) {
6416 default_candidate = _get_default_local_candidate_locked (agent, stream,
6418 if (default_candidate)
6419 rtp = default_candidate->addr;
6420 } else if (component->id == NICE_COMPONENT_TYPE_RTCP) {
6421 default_candidate = _get_default_local_candidate_locked (agent, stream,
6423 if (default_candidate)
6424 rtcp = default_candidate->addr;
6428 nice_address_to_string (&rtp, ip4);
6429 g_string_append_printf (sdp, "m=%s %d ICE/SDP\n",
6430 stream->name ? stream->name : "-", nice_address_get_port (&rtp));
6431 g_string_append_printf (sdp, "c=IN IP4 %s\n", ip4);
6432 if (nice_address_get_port (&rtcp) != 0)
6433 g_string_append_printf (sdp, "a=rtcp:%d\n",
6434 nice_address_get_port (&rtcp));
6437 g_string_append_printf (sdp, "a=ice-ufrag:%s\n", stream->local_ufrag);
6438 g_string_append_printf (sdp, "a=ice-pwd:%s\n", stream->local_password);
6440 for (i = stream->components; i; i = i->next) {
6441 NiceComponent *component = i->data;
6443 for (j = component->local_candidates; j; j = j->next) {
6444 NiceCandidate *candidate = j->data;
6446 if (agent->force_relay && candidate->type != NICE_CANDIDATE_TYPE_RELAYED)
6449 _generate_candidate_sdp (agent, candidate, sdp);
6450 g_string_append (sdp, "\n");
6455 NICEAPI_EXPORT gchar *
6456 nice_agent_generate_local_sdp (NiceAgent *agent)
6458 GString * sdp = g_string_new (NULL);
6461 g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
6465 for (i = agent->streams; i; i = i->next) {
6466 NiceStream *stream = i->data;
6468 _generate_stream_sdp (agent, stream, sdp, TRUE);
6471 agent_unlock_and_emit (agent);
6473 return g_string_free (sdp, FALSE);
6476 NICEAPI_EXPORT gchar *
6477 nice_agent_generate_local_stream_sdp (NiceAgent *agent, guint stream_id,
6478 gboolean include_non_ice)
6480 GString *sdp = NULL;
6484 g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
6485 g_return_val_if_fail (stream_id >= 1, NULL);
6489 stream = agent_find_stream (agent, stream_id);
6493 sdp = g_string_new (NULL);
6494 _generate_stream_sdp (agent, stream, sdp, include_non_ice);
6495 ret = g_string_free (sdp, FALSE);
6498 agent_unlock_and_emit (agent);
6503 NICEAPI_EXPORT gchar *
6504 nice_agent_generate_local_candidate_sdp (NiceAgent *agent,
6505 NiceCandidate *candidate)
6507 GString *sdp = NULL;
6509 g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
6510 g_return_val_if_fail (candidate != NULL, NULL);
6514 sdp = g_string_new (NULL);
6515 _generate_candidate_sdp (agent, candidate, sdp);
6517 agent_unlock_and_emit (agent);
6519 return g_string_free (sdp, FALSE);
6523 nice_agent_parse_remote_sdp (NiceAgent *agent, const gchar *sdp)
6525 NiceStream *current_stream = NULL;
6526 gchar **sdp_lines = NULL;
6527 GSList *stream_item = NULL;
6531 g_return_val_if_fail (NICE_IS_AGENT (agent), -1);
6532 g_return_val_if_fail (sdp != NULL, -1);
6536 sdp_lines = g_strsplit (sdp, "\n", 0);
6537 for (i = 0; sdp_lines && sdp_lines[i]; i++) {
6538 if (g_str_has_prefix (sdp_lines[i], "m=")) {
6539 if (stream_item == NULL)
6540 stream_item = agent->streams;
6542 stream_item = stream_item->next;
6544 g_critical("More streams in SDP than in agent");
6548 current_stream = stream_item->data;
6549 } else if (g_str_has_prefix (sdp_lines[i], "a=ice-ufrag:")) {
6550 if (current_stream == NULL) {
6554 g_strlcpy (current_stream->remote_ufrag, sdp_lines[i] + 12,
6555 NICE_STREAM_MAX_UFRAG);
6556 } else if (g_str_has_prefix (sdp_lines[i], "a=ice-pwd:")) {
6557 if (current_stream == NULL) {
6561 g_strlcpy (current_stream->remote_password, sdp_lines[i] + 10,
6562 NICE_STREAM_MAX_PWD);
6563 } else if (g_str_has_prefix (sdp_lines[i], "a=candidate:")) {
6564 NiceCandidate *candidate = NULL;
6565 NiceComponent *component = NULL;
6566 GSList *cands = NULL;
6569 if (current_stream == NULL) {
6573 candidate = nice_agent_parse_remote_candidate_sdp (agent,
6574 current_stream->id, sdp_lines[i]);
6575 if (candidate == NULL) {
6580 if (!agent_find_component (agent, candidate->stream_id,
6581 candidate->component_id, NULL, &component)) {
6582 nice_candidate_free (candidate);
6586 cands = g_slist_prepend (cands, candidate);
6587 added = _set_remote_candidates_locked (agent, current_stream,
6589 g_slist_free_full(cands, (GDestroyNotify)&nice_candidate_free);
6597 g_strfreev(sdp_lines);
6599 agent_unlock_and_emit (agent);
6604 NICEAPI_EXPORT GSList *
6605 nice_agent_parse_remote_stream_sdp (NiceAgent *agent, guint stream_id,
6606 const gchar *sdp, gchar **ufrag, gchar **pwd)
6608 NiceStream *stream = NULL;
6609 gchar **sdp_lines = NULL;
6610 GSList *candidates = NULL;
6613 g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
6614 g_return_val_if_fail (stream_id >= 1, NULL);
6615 g_return_val_if_fail (sdp != NULL, NULL);
6619 stream = agent_find_stream (agent, stream_id);
6620 if (stream == NULL) {
6624 sdp_lines = g_strsplit (sdp, "\n", 0);
6625 for (i = 0; sdp_lines && sdp_lines[i]; i++) {
6626 if (ufrag && g_str_has_prefix (sdp_lines[i], "a=ice-ufrag:")) {
6627 *ufrag = g_strdup (sdp_lines[i] + 12);
6628 } else if (pwd && g_str_has_prefix (sdp_lines[i], "a=ice-pwd:")) {
6629 *pwd = g_strdup (sdp_lines[i] + 10);
6630 } else if (g_str_has_prefix (sdp_lines[i], "a=candidate:")) {
6631 NiceCandidate *candidate = NULL;
6633 candidate = nice_agent_parse_remote_candidate_sdp (agent, stream->id,
6635 if (candidate == NULL) {
6636 g_slist_free_full(candidates, (GDestroyNotify)&nice_candidate_free);
6640 candidates = g_slist_prepend (candidates, candidate);
6646 g_strfreev(sdp_lines);
6648 agent_unlock_and_emit (agent);
6653 NICEAPI_EXPORT NiceCandidate *
6654 nice_agent_parse_remote_candidate_sdp (NiceAgent *agent, guint stream_id,
6657 NiceCandidate *candidate = NULL;
6659 gchar **tokens = NULL;
6660 const gchar *foundation = NULL;
6661 guint component_id = 0;
6662 const gchar *transport = NULL;
6663 guint32 priority = 0;
6664 const gchar *addr = NULL;
6666 const gchar *type = NULL;
6667 const gchar *tcptype = NULL;
6668 const gchar *raddr = NULL;
6670 static const gchar *type_names[] = {"host", "srflx", "prflx", "relay"};
6671 NiceCandidateTransport ctransport;
6674 g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
6675 g_return_val_if_fail (stream_id >= 1, NULL);
6676 g_return_val_if_fail (sdp != NULL, NULL);
6678 if (!g_str_has_prefix (sdp, "a=candidate:"))
6681 tokens = g_strsplit (sdp + 12, " ", 0);
6682 for (i = 0; tokens && tokens[i]; i++) {
6685 foundation = tokens[i];
6688 component_id = (guint) g_ascii_strtoull (tokens[i], NULL, 10);
6691 transport = tokens[i];
6694 priority = (guint32) g_ascii_strtoull (tokens[i], NULL, 10);
6700 port = (guint16) g_ascii_strtoull (tokens[i], NULL, 10);
6703 if (tokens[i + 1] == NULL)
6706 if (g_strcmp0 (tokens[i], "typ") == 0) {
6707 type = tokens[i + 1];
6708 } else if (g_strcmp0 (tokens[i], "raddr") == 0) {
6709 raddr = tokens[i + 1];
6710 } else if (g_strcmp0 (tokens[i], "rport") == 0) {
6711 rport = (guint16) g_ascii_strtoull (tokens[i + 1], NULL, 10);
6712 } else if (g_strcmp0 (tokens[i], "tcptype") == 0) {
6713 tcptype = tokens[i + 1];
6723 for (i = 0; i < G_N_ELEMENTS (type_names); i++) {
6724 if (g_strcmp0 (type, type_names[i]) == 0) {
6732 if (g_ascii_strcasecmp (transport, "UDP") == 0)
6733 ctransport = NICE_CANDIDATE_TRANSPORT_UDP;
6734 else if (g_ascii_strcasecmp (transport, "TCP-SO") == 0)
6735 ctransport = NICE_CANDIDATE_TRANSPORT_TCP_SO;
6736 else if (g_ascii_strcasecmp (transport, "TCP-ACT") == 0)
6737 ctransport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
6738 else if (g_ascii_strcasecmp (transport, "TCP-PASS") == 0)
6739 ctransport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
6740 else if (g_ascii_strcasecmp (transport, "TCP") == 0) {
6741 if (g_ascii_strcasecmp (tcptype, "so") == 0)
6742 ctransport = NICE_CANDIDATE_TRANSPORT_TCP_SO;
6743 else if (g_ascii_strcasecmp (tcptype, "active") == 0)
6744 ctransport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
6745 else if (g_ascii_strcasecmp (tcptype, "passive") == 0)
6746 ctransport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
6752 candidate = nice_candidate_new(ntype);
6753 candidate->component_id = component_id;
6754 candidate->stream_id = stream_id;
6755 candidate->transport = ctransport;
6756 g_strlcpy(candidate->foundation, foundation, NICE_CANDIDATE_MAX_FOUNDATION);
6757 candidate->priority = priority;
6759 if (!nice_address_set_from_string (&candidate->addr, addr)) {
6760 nice_candidate_free (candidate);
6764 nice_address_set_port (&candidate->addr, port);
6766 if (raddr && rport) {
6767 if (!nice_address_set_from_string (&candidate->base_addr, raddr)) {
6768 nice_candidate_free (candidate);
6772 nice_address_set_port (&candidate->base_addr, rport);
6783 NICEAPI_EXPORT GIOStream *
6784 nice_agent_get_io_stream (NiceAgent *agent, guint stream_id,
6787 GIOStream *iostream = NULL;
6788 NiceComponent *component;
6790 g_return_val_if_fail (NICE_IS_AGENT (agent), NULL);
6791 g_return_val_if_fail (stream_id >= 1, NULL);
6792 g_return_val_if_fail (component_id >= 1, NULL);
6794 g_return_val_if_fail (agent->reliable, NULL);
6798 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
6801 if (component->iostream == NULL)
6802 component->iostream = nice_io_stream_new (agent, stream_id, component_id);
6804 iostream = g_object_ref (component->iostream);
6807 agent_unlock_and_emit (agent);
6812 NICEAPI_EXPORT gboolean
6813 nice_agent_forget_relays (NiceAgent *agent, guint stream_id, guint component_id)
6815 NiceComponent *component;
6816 gboolean ret = TRUE;
6818 g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE);
6819 g_return_val_if_fail (stream_id >= 1, FALSE);
6820 g_return_val_if_fail (component_id >= 1, FALSE);
6824 if (!agent_find_component (agent, stream_id, component_id, NULL, &component)) {
6829 nice_component_clean_turn_servers (agent, component);
6832 agent_unlock_and_emit (agent);
6837 /* Helper function to allow us to send connchecks reliably.
6838 * If the transport is reliable, then we request a reliable send, which will
6839 * either send the data, or queue it in the case of unestablished http/socks5
6840 * proxies or tcp-turn. If the transport is not reliable, then it could be an
6841 * unreliable tcp-bsd, so we still try a reliable send to see if it can succeed
6842 * meaning the message was queued, or if it failed, then it was either udp-bsd
6843 * or turn and so we retry with a non reliable send and let the retransmissions
6844 * take care of the rest.
6845 * This is in order to avoid having to retransmit something if the underlying
6846 * socket layer can queue the message and send it once a connection is
6850 agent_socket_send (NiceSocket *sock, const NiceAddress *addr, gsize len,
6853 if (nice_socket_is_reliable (sock)) {
6854 guint16 rfc4571_frame = htons (len);
6855 GOutputVector local_buf[2] = {{&rfc4571_frame, 2}, { buf, len }};
6856 NiceOutputMessage local_message = { local_buf, 2};
6859 /* ICE-TCP requires that all packets be framed with RFC4571 */
6860 ret = nice_socket_send_messages_reliable (sock, addr, &local_message, 1);
6865 gssize ret = nice_socket_send_reliable (sock, addr, len, buf);
6867 ret = nice_socket_send (sock, addr, len, buf);
6873 nice_agent_get_component_state (NiceAgent *agent,
6874 guint stream_id, guint component_id)
6876 NiceComponentState state = NICE_COMPONENT_STATE_FAILED;
6877 NiceComponent *component;
6881 if (agent_find_component (agent, stream_id, component_id, NULL, &component))
6882 state = component->state;
6884 agent_unlock (agent);
6890 nice_agent_peer_candidate_gathering_done (NiceAgent *agent, guint stream_id)
6893 gboolean result = FALSE;
6897 stream = agent_find_stream (agent, stream_id);
6899 stream->peer_gathering_done = TRUE;
6903 agent_unlock (agent);
6909 on_agent_refreshes_pruned (NiceAgent *agent, gpointer user_data)
6911 GTask *task = user_data;
6913 /* This is called from a timeout cb with agent lock held */
6915 agent_unlock (agent);
6917 g_task_return_boolean (task, TRUE);
6918 g_object_unref (task);
6922 return G_SOURCE_REMOVE;
6926 nice_agent_close_async (NiceAgent *agent, GAsyncReadyCallback callback,
6927 gpointer callback_data)
6931 task = g_task_new (agent, NULL, callback, callback_data);
6932 g_task_set_source_tag (task, nice_agent_close_async);
6936 refresh_prune_agent_async (agent, on_agent_refreshes_pruned, task);
6938 agent_unlock (agent);
6942 NICEAPI_EXPORT GPtrArray *
6943 nice_agent_get_sockets (NiceAgent *agent, guint stream_id, guint component_id)
6945 GPtrArray *array = NULL;
6946 NiceComponent *component;
6949 if (agent_find_component (agent, stream_id, component_id, NULL, &component))
6950 array = nice_component_get_sockets (component);
6951 agent_unlock (agent);