wtf.. should not set added to -1 since we continue adding other candidates and e...
[sipe-libnice.git] / agent / agent.c
blob30ec34a0ff0e5697b899cda15a11181db8745e11
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2006-2010 Collabora Ltd.
5 * Contact: Youness Alaoui
6 * (C) 2006-2010 Nokia Corporation. All rights reserved.
7 * Contact: Kai Vehmanen
9 * The contents of this file are subject to the Mozilla Public License Version
10 * 1.1 (the "License"); you may not use this file except in compliance with
11 * the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS" basis,
15 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 * for the specific language governing rights and limitations under the
17 * License.
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.
24 * Contributors:
25 * Dafydd Harries, Collabora Ltd.
26 * Youness Alaoui, Collabora Ltd.
27 * Kai Vehmanen, Nokia
29 * Alternatively, the contents of this file may be used under the terms of the
30 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
31 * case the provisions of LGPL are applicable instead of those above. If you
32 * wish to allow use of your version of this file only under the terms of the
33 * LGPL and not to allow others to use your version of this file under the
34 * MPL, indicate your decision by deleting the provisions above and replace
35 * them with the notice and other provisions required by the LGPL. If you do
36 * not delete the provisions above, a recipient may use your version of this
37 * file under either the MPL or the LGPL.
41 #ifdef HAVE_CONFIG_H
42 # include <config.h>
43 #else
44 #define NICEAPI_EXPORT
45 #endif
47 #include <glib.h>
49 #include <string.h>
50 #include <errno.h>
52 #ifdef G_OS_WIN32
53 #include <winsock2.h>
54 #else
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
58 #endif
60 #include "debug.h"
62 #include "socket.h"
63 #include "stun/usages/turn.h"
64 #include "candidate.h"
65 #include "component.h"
66 #include "conncheck.h"
67 #include "discovery.h"
68 #include "agent.h"
69 #include "agent-priv.h"
70 #include "agent-signals-marshal.h"
72 #include "stream.h"
73 #include "interfaces.h"
75 #include "pseudotcp.h"
77 /* This is the max size of a UDP packet
78 * will it work tcp relaying??
80 #define MAX_BUFFER_SIZE 65536
81 #define DEFAULT_STUN_PORT 3478
82 #define DEFAULT_UPNP_TIMEOUT 200
84 #define MAX_TCP_MTU 1400 /* Use 1400 because of VPNs and we assume IEE 802.3 */
86 G_DEFINE_TYPE (NiceAgent, nice_agent, G_TYPE_OBJECT);
88 enum
90 PROP_COMPATIBILITY = 1,
91 PROP_MAIN_CONTEXT,
92 PROP_STUN_SERVER,
93 PROP_STUN_SERVER_PORT,
94 PROP_CONTROLLING_MODE,
95 PROP_FULL_MODE,
96 PROP_STUN_PACING_TIMER,
97 PROP_MAX_CONNECTIVITY_CHECKS,
98 PROP_PROXY_TYPE,
99 PROP_PROXY_IP,
100 PROP_PROXY_PORT,
101 PROP_PROXY_USERNAME,
102 PROP_PROXY_PASSWORD,
103 PROP_UPNP,
104 PROP_UPNP_TIMEOUT,
105 PROP_RELIABLE
109 enum
111 SIGNAL_COMPONENT_STATE_CHANGED,
112 SIGNAL_CANDIDATE_GATHERING_DONE,
113 SIGNAL_NEW_SELECTED_PAIR,
114 SIGNAL_NEW_CANDIDATE,
115 SIGNAL_NEW_REMOTE_CANDIDATE,
116 SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED,
117 SIGNAL_RELIABLE_TRANSPORT_WRITABLE,
118 N_SIGNALS,
121 static guint signals[N_SIGNALS];
123 static GStaticRecMutex agent_mutex = G_STATIC_REC_MUTEX_INIT; /* Mutex used for thread-safe lib */
125 static gboolean priv_attach_stream_component (NiceAgent *agent,
126 Stream *stream,
127 Component *component);
128 static void priv_detach_stream_component (Stream *stream, Component *component);
130 static void priv_free_upnp (NiceAgent *agent);
133 void agent_lock (void)
135 g_static_rec_mutex_lock (&agent_mutex);
138 void agent_unlock (void)
140 g_static_rec_mutex_unlock (&agent_mutex);
145 StunUsageIceCompatibility
146 agent_to_ice_compatibility (NiceAgent *agent)
148 return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
149 STUN_USAGE_ICE_COMPATIBILITY_GOOGLE :
150 agent->compatibility == NICE_COMPATIBILITY_MSN ?
151 STUN_USAGE_ICE_COMPATIBILITY_MSN :
152 STUN_USAGE_ICE_COMPATIBILITY_RFC5245;
156 StunUsageTurnCompatibility
157 agent_to_turn_compatibility (NiceAgent *agent)
159 return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
160 STUN_USAGE_TURN_COMPATIBILITY_GOOGLE :
161 agent->compatibility == NICE_COMPATIBILITY_MSN ?
162 STUN_USAGE_TURN_COMPATIBILITY_MSN :
163 agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
164 STUN_USAGE_TURN_COMPATIBILITY_MSN : STUN_USAGE_TURN_COMPATIBILITY_DRAFT9;
167 NiceTurnSocketCompatibility
168 agent_to_turn_socket_compatibility (NiceAgent *agent)
170 return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
171 NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE :
172 agent->compatibility == NICE_COMPATIBILITY_MSN ?
173 NICE_TURN_SOCKET_COMPATIBILITY_MSN :
174 agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
175 NICE_TURN_SOCKET_COMPATIBILITY_MSN :
176 NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9;
179 Stream *agent_find_stream (NiceAgent *agent, guint stream_id)
181 GSList *i;
183 for (i = agent->streams; i; i = i->next)
185 Stream *s = i->data;
187 if (s->id == stream_id)
188 return s;
191 return NULL;
195 gboolean
196 agent_find_component (
197 NiceAgent *agent,
198 guint stream_id,
199 guint component_id,
200 Stream **stream,
201 Component **component)
203 Stream *s;
204 Component *c;
206 s = agent_find_stream (agent, stream_id);
208 if (s == NULL)
209 return FALSE;
211 c = stream_find_component_by_id (s, component_id);
213 if (c == NULL)
214 return FALSE;
216 if (stream)
217 *stream = s;
219 if (component)
220 *component = c;
222 return TRUE;
226 static void
227 nice_agent_dispose (GObject *object);
229 static void
230 nice_agent_get_property (
231 GObject *object,
232 guint property_id,
233 GValue *value,
234 GParamSpec *pspec);
236 static void
237 nice_agent_set_property (
238 GObject *object,
239 guint property_id,
240 const GValue *value,
241 GParamSpec *pspec);
244 static void
245 nice_agent_class_init (NiceAgentClass *klass)
247 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
249 gobject_class->get_property = nice_agent_get_property;
250 gobject_class->set_property = nice_agent_set_property;
251 gobject_class->dispose = nice_agent_dispose;
253 /* install properties */
255 * NiceAgent:main-context:
257 * A GLib main context is needed for all timeouts used by libnice.
258 * This is a property being set by the nice_agent_new() call.
260 g_object_class_install_property (gobject_class, PROP_MAIN_CONTEXT,
261 g_param_spec_pointer (
262 "main-context",
263 "The GMainContext to use for timeouts",
264 "The GMainContext to use for timeouts",
265 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
268 * NiceAgent:compatibility:
270 * The Nice agent can work in various compatibility modes depending on
271 * what the application/peer needs.
272 * <para> See also: #NiceCompatibility</para>
274 g_object_class_install_property (gobject_class, PROP_COMPATIBILITY,
275 g_param_spec_uint (
276 "compatibility",
277 "ICE specification compatibility",
278 "The compatibility mode for the agent",
279 NICE_COMPATIBILITY_RFC5245, NICE_COMPATIBILITY_LAST,
280 NICE_COMPATIBILITY_RFC5245,
281 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
283 g_object_class_install_property (gobject_class, PROP_STUN_SERVER,
284 g_param_spec_string (
285 "stun-server",
286 "STUN server",
287 "The STUN server used to obtain server-reflexive candidates",
288 NULL,
289 G_PARAM_READWRITE));
291 g_object_class_install_property (gobject_class, PROP_STUN_SERVER_PORT,
292 g_param_spec_uint (
293 "stun-server-port",
294 "STUN server port",
295 "The STUN server used to obtain server-reflexive candidates",
296 1, 65536,
297 1, /* not a construct property, ignored */
298 G_PARAM_READWRITE));
300 g_object_class_install_property (gobject_class, PROP_CONTROLLING_MODE,
301 g_param_spec_boolean (
302 "controlling-mode",
303 "ICE controlling mode",
304 "Whether the agent is in controlling mode",
305 FALSE, /* not a construct property, ignored */
306 G_PARAM_READWRITE));
308 g_object_class_install_property (gobject_class, PROP_FULL_MODE,
309 g_param_spec_boolean (
310 "full-mode",
311 "ICE full mode",
312 "Whether agent runs in ICE full mode",
313 TRUE, /* use full mode by default */
314 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
316 g_object_class_install_property (gobject_class, PROP_STUN_PACING_TIMER,
317 g_param_spec_uint (
318 "stun-pacing-timer",
319 "STUN pacing timer",
320 "Timer 'Ta' (msecs) used in the IETF ICE specification for pacing "
321 "candidate gathering and sending of connectivity checks",
322 1, 0xffffffff,
323 NICE_AGENT_TIMER_TA_DEFAULT,
324 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
326 /* note: according to spec recommendation in sect 5.7.3 (ID-19) */
327 g_object_class_install_property (gobject_class, PROP_MAX_CONNECTIVITY_CHECKS,
328 g_param_spec_uint (
329 "max-connectivity-checks",
330 "Maximum number of connectivity checks",
331 "Upper limit for the total number of connectivity checks performed",
332 0, 0xffffffff,
333 0, /* default set in init */
334 G_PARAM_READWRITE));
337 * NiceAgent:proxy-ip:
339 * The proxy server IP used to bypass a proxy firewall
341 * Since: 0.0.4
343 g_object_class_install_property (gobject_class, PROP_PROXY_IP,
344 g_param_spec_string (
345 "proxy-ip",
346 "Proxy server IP",
347 "The proxy server IP used to bypass a proxy firewall",
348 NULL,
349 G_PARAM_READWRITE));
352 * NiceAgent:proxy-port:
354 * The proxy server port used to bypass a proxy firewall
356 * Since: 0.0.4
358 g_object_class_install_property (gobject_class, PROP_PROXY_PORT,
359 g_param_spec_uint (
360 "proxy-port",
361 "Proxy server port",
362 "The Proxy server port used to bypass a proxy firewall",
363 1, 65536,
365 G_PARAM_READWRITE));
368 * NiceAgent:proxy-type:
370 * The type of proxy set in the proxy-ip property
372 * Since: 0.0.4
374 g_object_class_install_property (gobject_class, PROP_PROXY_TYPE,
375 g_param_spec_uint (
376 "proxy-type",
377 "Type of proxy to use",
378 "The type of proxy set in the proxy-ip property",
379 NICE_PROXY_TYPE_NONE, NICE_PROXY_TYPE_LAST,
380 NICE_PROXY_TYPE_NONE,
381 G_PARAM_READWRITE));
384 * NiceAgent:proxy-username:
386 * The username used to authenticate with the proxy
388 * Since: 0.0.4
390 g_object_class_install_property (gobject_class, PROP_PROXY_USERNAME,
391 g_param_spec_string (
392 "proxy-username",
393 "Proxy server username",
394 "The username used to authenticate with the proxy",
395 NULL,
396 G_PARAM_READWRITE));
399 * NiceAgent:proxy-password:
401 * The password used to authenticate with the proxy
403 * Since: 0.0.4
405 g_object_class_install_property (gobject_class, PROP_PROXY_PASSWORD,
406 g_param_spec_string (
407 "proxy-password",
408 "Proxy server password",
409 "The password used to authenticate with the proxy",
410 NULL,
411 G_PARAM_READWRITE));
414 * NiceAgent:upnp:
416 * Whether the agent should use UPnP to open a port in the router and
417 * get the external IP
419 * Since: 0.0.7
421 g_object_class_install_property (gobject_class, PROP_UPNP,
422 g_param_spec_boolean (
423 "upnp",
424 #ifdef HAVE_GUPNP
425 "Use UPnP",
426 "Whether the agent should use UPnP to open a port in the router and "
427 "get the external IP",
428 #else
429 "Use UPnP (disabled in build)",
430 "Does nothing because libnice was not built with UPnP support",
431 #endif
432 TRUE, /* enable UPnP by default */
433 G_PARAM_READWRITE| G_PARAM_CONSTRUCT));
436 * NiceAgent:upnp-timeout:
438 * The maximum amount of time to wait for UPnP discovery to finish before
439 * signaling the #NiceAgent::candidate-gathering-done signal
441 * Since: 0.0.7
443 g_object_class_install_property (gobject_class, PROP_UPNP_TIMEOUT,
444 g_param_spec_uint (
445 "upnp-timeout",
446 #ifdef HAVE_GUPNP
447 "Timeout for UPnP discovery",
448 "The maximum amount of time to wait for UPnP discovery to finish before "
449 "signaling the candidate-gathering-done signal",
450 #else
451 "Timeout for UPnP discovery (disabled in build)",
452 "Does nothing because libnice was not built with UPnP support",
453 #endif
454 100, 60000,
455 DEFAULT_UPNP_TIMEOUT,
456 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
459 * NiceAgent:reliable:
461 * Whether the agent should use PseudoTcp to ensure a reliable transport
462 * of messages
464 * Since: 0.0.11
466 g_object_class_install_property (gobject_class, PROP_RELIABLE,
467 g_param_spec_boolean (
468 "reliable",
469 "reliable mode",
470 "Whether the agent should use PseudoTcp to ensure a reliable transport"
471 "of messages",
472 FALSE,
473 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
475 /* install signals */
478 * NiceAgent::component-state-changed
479 * @agent: The #NiceAgent object
480 * @stream_id: The ID of the stream
481 * @component_id: The ID of the component
482 * @state: The #NiceComponentState of the component
484 * This signal is fired whenever a component's state changes
486 signals[SIGNAL_COMPONENT_STATE_CHANGED] =
487 g_signal_new (
488 "component-state-changed",
489 G_OBJECT_CLASS_TYPE (klass),
490 G_SIGNAL_RUN_LAST,
492 NULL,
493 NULL,
494 agent_marshal_VOID__UINT_UINT_UINT,
495 G_TYPE_NONE,
497 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
498 G_TYPE_INVALID);
501 * NiceAgent::candidate-gathering-done:
502 * @agent: The #NiceAgent object
503 * @stream_id: The ID of the stream
505 * This signal is fired whenever a stream has finished gathering its
506 * candidates after a call to nice_agent_gather_candidates()
508 signals[SIGNAL_CANDIDATE_GATHERING_DONE] =
509 g_signal_new (
510 "candidate-gathering-done",
511 G_OBJECT_CLASS_TYPE (klass),
512 G_SIGNAL_RUN_LAST,
514 NULL,
515 NULL,
516 agent_marshal_VOID__UINT,
517 G_TYPE_NONE,
519 G_TYPE_UINT, G_TYPE_INVALID);
522 * NiceAgent::new-selected-pair
523 * @agent: The #NiceAgent object
524 * @stream_id: The ID of the stream
525 * @component_id: The ID of the component
526 * @lfoundation: The local foundation of the selected candidate pair
527 * @rfoundation: The remote foundation of the selected candidate pair
529 * This signal is fired once a candidate pair is selected for data transfer for
530 * a stream's component
532 signals[SIGNAL_NEW_SELECTED_PAIR] =
533 g_signal_new (
534 "new-selected-pair",
535 G_OBJECT_CLASS_TYPE (klass),
536 G_SIGNAL_RUN_LAST,
538 NULL,
539 NULL,
540 agent_marshal_VOID__UINT_UINT_STRING_STRING,
541 G_TYPE_NONE,
543 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING,
544 G_TYPE_INVALID);
547 * NiceAgent::new-candidate
548 * @agent: The #NiceAgent object
549 * @stream_id: The ID of the stream
550 * @component_id: The ID of the component
551 * @foundation: The foundation of the new candidate
553 * This signal is fired when the agent discovers a new candidate
554 * <para> See also: #NiceAgent::candidate-gathering-done </para>
556 signals[SIGNAL_NEW_CANDIDATE] =
557 g_signal_new (
558 "new-candidate",
559 G_OBJECT_CLASS_TYPE (klass),
560 G_SIGNAL_RUN_LAST,
562 NULL,
563 NULL,
564 agent_marshal_VOID__UINT_UINT_STRING,
565 G_TYPE_NONE,
567 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
568 G_TYPE_INVALID);
571 * NiceAgent::new-remote-candidate
572 * @agent: The #NiceAgent object
573 * @stream_id: The ID of the stream
574 * @component_id: The ID of the component
575 * @foundation: The foundation of the new candidate
577 * This signal is fired when the agent discovers a new remote candidate.
578 * This can happen with peer reflexive candidates.
580 signals[SIGNAL_NEW_REMOTE_CANDIDATE] =
581 g_signal_new (
582 "new-remote-candidate",
583 G_OBJECT_CLASS_TYPE (klass),
584 G_SIGNAL_RUN_LAST,
586 NULL,
587 NULL,
588 agent_marshal_VOID__UINT_UINT_STRING,
589 G_TYPE_NONE,
591 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
592 G_TYPE_INVALID);
595 * NiceAgent::initial-binding-request-received
596 * @agent: The #NiceAgent object
597 * @stream_id: The ID of the stream
599 * This signal is fired when we received our first binding request from
600 * the peer.
602 signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED] =
603 g_signal_new (
604 "initial-binding-request-received",
605 G_OBJECT_CLASS_TYPE (klass),
606 G_SIGNAL_RUN_LAST,
608 NULL,
609 NULL,
610 agent_marshal_VOID__UINT,
611 G_TYPE_NONE,
613 G_TYPE_UINT,
614 G_TYPE_INVALID);
617 * NiceAgent::reliable-transport-writable
618 * @agent: The #NiceAgent object
619 * @stream_id: The ID of the stream
620 * @component_id: The ID of the component
622 * This signal is fired on the reliable #NiceAgent when the underlying reliable
623 * transport becomes writable.
624 * This signal is only emitted when the nice_agent_send() function returns less
625 * bytes than requested to send (or -1) and once when the connection
626 * is established.
628 * Since: 0.0.11
630 signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE] =
631 g_signal_new (
632 "reliable-transport-writable",
633 G_OBJECT_CLASS_TYPE (klass),
634 G_SIGNAL_RUN_LAST,
636 NULL,
637 NULL,
638 agent_marshal_VOID__UINT_UINT,
639 G_TYPE_NONE,
641 G_TYPE_UINT, G_TYPE_UINT,
642 G_TYPE_INVALID);
645 /* Init debug options depending on env variables */
646 nice_debug_init ();
649 static void priv_generate_tie_breaker (NiceAgent *agent)
651 nice_rng_generate_bytes (agent->rng, 8, (gchar*)&agent->tie_breaker);
654 static void
655 nice_agent_init (NiceAgent *agent)
657 agent->next_candidate_id = 1;
658 agent->next_stream_id = 1;
660 /* set defaults; not construct params, so set here */
661 agent->stun_server_port = DEFAULT_STUN_PORT;
662 agent->controlling_mode = TRUE;
663 agent->max_conn_checks = NICE_AGENT_MAX_CONNECTIVITY_CHECKS_DEFAULT;
665 agent->discovery_list = NULL;
666 agent->discovery_unsched_items = 0;
667 agent->discovery_timer_source = NULL;
668 agent->conncheck_timer_source = NULL;
669 agent->keepalive_timer_source = NULL;
670 agent->refresh_list = NULL;
671 agent->media_after_tick = FALSE;
672 agent->software_attribute = NULL;
674 agent->compatibility = NICE_COMPATIBILITY_RFC5245;
675 agent->reliable = FALSE;
677 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
678 STUN_COMPATIBILITY_RFC5389,
679 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
680 STUN_AGENT_USAGE_USE_FINGERPRINT);
682 agent->rng = nice_rng_new ();
683 priv_generate_tie_breaker (agent);
687 NICEAPI_EXPORT NiceAgent *
688 nice_agent_new (GMainContext *ctx, NiceCompatibility compat)
690 NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
691 "compatibility", compat,
692 "main-context", ctx,
693 "reliable", FALSE,
694 NULL);
696 return agent;
700 NICEAPI_EXPORT NiceAgent *
701 nice_agent_new_reliable (GMainContext *ctx, NiceCompatibility compat)
703 NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
704 "compatibility", compat,
705 "main-context", ctx,
706 "reliable", TRUE,
707 NULL);
709 return agent;
713 static void
714 nice_agent_get_property (
715 GObject *object,
716 guint property_id,
717 GValue *value,
718 GParamSpec *pspec)
720 NiceAgent *agent = NICE_AGENT (object);
722 agent_lock();
724 switch (property_id)
726 case PROP_MAIN_CONTEXT:
727 g_value_set_pointer (value, agent->main_context);
728 break;
730 case PROP_COMPATIBILITY:
731 g_value_set_uint (value, agent->compatibility);
732 break;
734 case PROP_STUN_SERVER:
735 g_value_set_string (value, agent->stun_server_ip);
736 break;
738 case PROP_STUN_SERVER_PORT:
739 g_value_set_uint (value, agent->stun_server_port);
740 break;
742 case PROP_CONTROLLING_MODE:
743 g_value_set_boolean (value, agent->controlling_mode);
744 break;
746 case PROP_FULL_MODE:
747 g_value_set_boolean (value, agent->full_mode);
748 break;
750 case PROP_STUN_PACING_TIMER:
751 g_value_set_uint (value, agent->timer_ta);
752 break;
754 case PROP_MAX_CONNECTIVITY_CHECKS:
755 g_value_set_uint (value, agent->max_conn_checks);
756 /* XXX: should we prune the list of already existing checks? */
757 break;
759 case PROP_PROXY_IP:
760 g_value_set_string (value, agent->proxy_ip);
761 break;
763 case PROP_PROXY_PORT:
764 g_value_set_uint (value, agent->proxy_port);
765 break;
767 case PROP_PROXY_TYPE:
768 g_value_set_uint (value, agent->proxy_type);
769 break;
771 case PROP_PROXY_USERNAME:
772 g_value_set_string (value, agent->proxy_username);
773 break;
775 case PROP_PROXY_PASSWORD:
776 g_value_set_string (value, agent->proxy_password);
777 break;
779 case PROP_UPNP:
780 #ifdef HAVE_GUPNP
781 g_value_set_boolean (value, agent->upnp_enabled);
782 #else
783 g_value_set_boolean (value, FALSE);
784 #endif
785 break;
787 case PROP_UPNP_TIMEOUT:
788 #ifdef HAVE_GUPNP
789 g_value_set_uint (value, agent->upnp_timeout);
790 #else
791 g_value_set_uint (value, DEFAULT_UPNP_TIMEOUT);
792 #endif
793 break;
795 case PROP_RELIABLE:
796 g_value_set_boolean (value, agent->reliable);
797 break;
799 default:
800 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
803 agent_unlock();
807 static void
808 nice_agent_set_property (
809 GObject *object,
810 guint property_id,
811 const GValue *value,
812 GParamSpec *pspec)
814 NiceAgent *agent = NICE_AGENT (object);
816 agent_lock();
818 switch (property_id)
820 case PROP_MAIN_CONTEXT:
821 agent->main_context = g_value_get_pointer (value);
822 if (agent->main_context != NULL)
823 g_main_context_ref (agent->main_context);
824 break;
826 case PROP_COMPATIBILITY:
827 agent->compatibility = g_value_get_uint (value);
828 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
829 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
830 STUN_COMPATIBILITY_RFC3489,
831 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
832 STUN_AGENT_USAGE_IGNORE_CREDENTIALS);
833 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN) {
834 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
835 STUN_COMPATIBILITY_RFC3489,
836 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
837 STUN_AGENT_USAGE_FORCE_VALIDATER);
838 } else if (agent->compatibility == NICE_COMPATIBILITY_WLM2009) {
839 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
840 STUN_COMPATIBILITY_WLM2009,
841 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
842 STUN_AGENT_USAGE_USE_FINGERPRINT);
843 } else {
844 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
845 STUN_COMPATIBILITY_RFC5389,
846 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
847 STUN_AGENT_USAGE_USE_FINGERPRINT);
849 stun_agent_set_software (&agent->stun_agent, agent->software_attribute);
851 break;
853 case PROP_STUN_SERVER:
854 agent->stun_server_ip = g_value_dup_string (value);
855 break;
857 case PROP_STUN_SERVER_PORT:
858 agent->stun_server_port = g_value_get_uint (value);
859 break;
861 case PROP_CONTROLLING_MODE:
862 agent->controlling_mode = g_value_get_boolean (value);
863 break;
865 case PROP_FULL_MODE:
866 agent->full_mode = g_value_get_boolean (value);
867 break;
869 case PROP_STUN_PACING_TIMER:
870 agent->timer_ta = g_value_get_uint (value);
871 break;
873 case PROP_MAX_CONNECTIVITY_CHECKS:
874 agent->max_conn_checks = g_value_get_uint (value);
875 break;
877 case PROP_PROXY_IP:
878 agent->proxy_ip = g_value_dup_string (value);
879 break;
881 case PROP_PROXY_PORT:
882 agent->proxy_port = g_value_get_uint (value);
883 break;
885 case PROP_PROXY_TYPE:
886 agent->proxy_type = g_value_get_uint (value);
887 break;
889 case PROP_PROXY_USERNAME:
890 agent->proxy_username = g_value_dup_string (value);
891 break;
893 case PROP_PROXY_PASSWORD:
894 agent->proxy_password = g_value_dup_string (value);
895 break;
897 case PROP_UPNP_TIMEOUT:
898 #ifdef HAVE_GUPNP
899 agent->upnp_timeout = g_value_get_uint (value);
900 #endif
901 break;
903 case PROP_UPNP:
904 #ifdef HAVE_GUPNP
905 agent->upnp_enabled = g_value_get_boolean (value);
906 #endif
907 break;
909 case PROP_RELIABLE:
910 agent->reliable = g_value_get_boolean (value);
911 break;
913 default:
914 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
917 agent_unlock();
922 static void priv_destroy_component_tcp (Component *component)
924 if (component->tcp_clock) {
925 g_source_destroy (component->tcp_clock);
926 g_source_unref (component->tcp_clock);
927 component->tcp_clock = NULL;
929 if (component->tcp) {
930 pseudo_tcp_socket_close (component->tcp, TRUE);
931 g_object_unref (component->tcp);
932 component->tcp = NULL;
934 if (component->tcp_data != NULL) {
935 g_slice_free (TcpUserData, component->tcp_data);
936 component->tcp_data = NULL;
940 static void priv_pseudo_tcp_error (NiceAgent *agent, Stream *stream,
941 Component *component)
943 if (component->tcp) {
944 agent_signal_component_state_change (agent, stream->id,
945 component->id, NICE_COMPONENT_STATE_FAILED);
946 priv_detach_stream_component (stream, component);
948 priv_destroy_component_tcp (component);
951 static void
952 adjust_tcp_clock (NiceAgent *agent, Stream *stream, Component *component);
955 static void
956 pseudo_tcp_socket_opened (PseudoTcpSocket *sock, gpointer user_data)
958 TcpUserData *data = (TcpUserData *)user_data;
959 NiceAgent *agent = data->agent;
960 Component *component = data->component;
961 Stream *stream = data->stream;
963 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket Opened", data->agent,
964 stream->id, component->id);
965 g_signal_emit (agent, signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE], 0,
966 stream->id, component->id);
969 static void
970 pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data)
972 TcpUserData *data = (TcpUserData *)user_data;
973 NiceAgent *agent = data->agent;
974 Component *component = data->component;
975 Stream *stream = data->stream;
976 gchar buf[MAX_BUFFER_SIZE];
977 gint len;
979 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket readable", agent,
980 stream->id, component->id);
982 component->tcp_readable = TRUE;
984 g_object_add_weak_pointer (G_OBJECT (sock), (gpointer *)&sock);
985 g_object_add_weak_pointer (G_OBJECT (agent), (gpointer *)&agent);
987 do {
988 if (component->g_source_io_cb)
989 len = pseudo_tcp_socket_recv (sock, buf, sizeof(buf));
990 else
991 len = 0;
993 if (len > 0) {
994 gpointer data = component->data;
995 gint sid = stream->id;
996 gint cid = component->id;
997 NiceAgentRecvFunc callback = component->g_source_io_cb;
998 /* Unlock the agent before calling the callback */
999 agent_unlock();
1000 callback (agent, sid, cid, len, buf, data);
1001 agent_lock();
1002 if (sock == NULL) {
1003 nice_debug ("PseudoTCP socket got destroyed in readable callback!");
1004 break;
1006 } else if (len < 0 &&
1007 pseudo_tcp_socket_get_error (sock) != EWOULDBLOCK) {
1008 /* Signal error */
1009 priv_pseudo_tcp_error (agent, stream, component);
1010 } else if (len < 0 &&
1011 pseudo_tcp_socket_get_error (sock) == EWOULDBLOCK){
1012 component->tcp_readable = FALSE;
1014 } while (len > 0);
1016 if (agent) {
1017 adjust_tcp_clock (agent, stream, component);
1018 g_object_remove_weak_pointer (G_OBJECT (agent), (gpointer *)&agent);
1019 } else {
1020 nice_debug ("Not calling adjust_tcp_clock.. agent got destroyed!");
1022 if (sock)
1023 g_object_remove_weak_pointer (G_OBJECT (sock), (gpointer *)&sock);
1026 static void
1027 pseudo_tcp_socket_writable (PseudoTcpSocket *sock, gpointer user_data)
1029 TcpUserData *data = (TcpUserData *)user_data;
1030 NiceAgent *agent = data->agent;
1031 Component *component = data->component;
1032 Stream *stream = data->stream;
1034 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket writable", data->agent,
1035 data->stream->id, data->component->id);
1036 g_signal_emit (agent, signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE], 0,
1037 stream->id, component->id);
1040 static void
1041 pseudo_tcp_socket_closed (PseudoTcpSocket *sock, guint32 err,
1042 gpointer user_data)
1044 TcpUserData *data = (TcpUserData *)user_data;
1045 NiceAgent *agent = data->agent;
1046 Component *component = data->component;
1047 Stream *stream = data->stream;
1049 nice_debug ("Agent %p: s%d:%d pseudo Tcp socket closed", agent,
1050 stream->id, component->id);
1051 priv_pseudo_tcp_error (agent, stream, component);
1055 static PseudoTcpWriteResult
1056 pseudo_tcp_socket_write_packet (PseudoTcpSocket *sock,
1057 const gchar *buffer, guint32 len, gpointer user_data)
1059 TcpUserData *data = (TcpUserData *)user_data;
1060 NiceAgent *agent = data->agent;
1061 Component *component = data->component;
1062 Stream *stream = data->stream;
1064 if (component->selected_pair.local != NULL) {
1065 NiceSocket *sock;
1066 NiceAddress *addr;
1068 #ifndef NDEBUG
1069 gchar tmpbuf[INET6_ADDRSTRLEN];
1070 nice_address_to_string (&component->selected_pair.remote->addr, tmpbuf);
1072 nice_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", agent,
1073 stream->id, component->id, len, tmpbuf,
1074 nice_address_get_port (&component->selected_pair.remote->addr));
1075 #endif
1077 sock = component->selected_pair.local->sockptr;
1078 addr = &component->selected_pair.remote->addr;
1079 if (nice_socket_send (sock, addr, len, buffer)) {
1080 return WR_SUCCESS;
1084 return WR_FAIL;
1088 static gboolean
1089 notify_pseudo_tcp_socket_clock (gpointer user_data)
1091 TcpUserData *data = (TcpUserData *)user_data;
1092 Component *component = data->component;
1093 Stream *stream = data->stream;
1094 NiceAgent *agent = data->agent;
1096 agent_lock();
1098 if (g_source_is_destroyed (g_main_current_source ())) {
1099 nice_debug ("Source was destroyed. "
1100 "Avoided race condition in notify_pseudo_tcp_socket_clock");
1101 agent_unlock ();
1102 return FALSE;
1104 if (component->tcp_clock) {
1105 g_source_destroy (component->tcp_clock);
1106 g_source_unref (component->tcp_clock);
1107 component->tcp_clock = NULL;
1110 pseudo_tcp_socket_notify_clock (component->tcp);
1111 adjust_tcp_clock (agent, stream, component);
1113 agent_unlock();
1115 return FALSE;
1118 static void
1119 adjust_tcp_clock (NiceAgent *agent, Stream *stream, Component *component)
1121 long timeout = 0;
1122 if (component->tcp) {
1123 if (pseudo_tcp_socket_get_next_clock (component->tcp, &timeout)) {
1124 if (component->tcp_clock) {
1125 g_source_destroy (component->tcp_clock);
1126 g_source_unref (component->tcp_clock);
1127 component->tcp_clock = NULL;
1129 component->tcp_clock = agent_timeout_add_with_context (agent,
1130 timeout, notify_pseudo_tcp_socket_clock, component->tcp_data);
1131 } else {
1132 nice_debug ("Agent %p: component %d pseudo tcp socket should be destroyed",
1133 agent, component->id);
1134 priv_pseudo_tcp_error (agent, stream, component);
1140 void agent_gathering_done (NiceAgent *agent)
1143 GSList *i, *j, *k, *l, *m;
1145 for (i = agent->streams; i; i = i->next) {
1146 Stream *stream = i->data;
1147 for (j = stream->components; j; j = j->next) {
1148 Component *component = j->data;
1150 for (k = component->local_candidates; k; k = k->next) {
1151 NiceCandidate *local_candidate = k->data;
1153 gchar tmpbuf[INET6_ADDRSTRLEN];
1154 nice_address_to_string (&local_candidate->addr, tmpbuf);
1155 nice_debug ("Agent %p: gathered local candidate : [%s]:%u"
1156 " for s%d/c%d. U/P '%s'/'%s'", agent,
1157 tmpbuf, nice_address_get_port (&local_candidate->addr),
1158 local_candidate->stream_id, local_candidate->component_id,
1159 local_candidate->username, local_candidate->password);
1161 for (l = component->remote_candidates; l; l = l->next) {
1162 NiceCandidate *remote_candidate = l->data;
1164 for (m = stream->conncheck_list; m; m = m->next) {
1165 CandidateCheckPair *p = m->data;
1167 if (p->local == local_candidate && p->remote == remote_candidate)
1168 break;
1170 if (m == NULL) {
1171 conn_check_add_for_candidate (agent, stream->id, component, remote_candidate);
1178 #ifdef HAVE_GUPNP
1179 if (agent->discovery_timer_source == NULL &&
1180 agent->upnp_timer_source == NULL) {
1181 agent_signal_gathering_done (agent);
1183 #else
1184 agent_signal_gathering_done (agent);
1185 #endif
1188 void agent_signal_gathering_done (NiceAgent *agent)
1190 GSList *i;
1192 for (i = agent->streams; i; i = i->next) {
1193 Stream *stream = i->data;
1194 if (stream->gathering) {
1195 stream->gathering = FALSE;
1196 g_signal_emit (agent, signals[SIGNAL_CANDIDATE_GATHERING_DONE], 0, stream->id);
1201 void agent_signal_initial_binding_request_received (NiceAgent *agent, Stream *stream)
1203 if (stream->initial_binding_request_received != TRUE) {
1204 stream->initial_binding_request_received = TRUE;
1205 g_signal_emit (agent, signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED], 0, stream->id);
1209 void agent_signal_new_selected_pair (NiceAgent *agent, guint stream_id, guint component_id, const gchar *local_foundation, const gchar *remote_foundation)
1211 Component *component;
1212 Stream *stream;
1213 gchar *lf_copy;
1214 gchar *rf_copy;
1216 if (!agent_find_component (agent, stream_id, component_id,
1217 &stream, &component))
1218 return;
1220 if (component->selected_pair.local->type == NICE_CANDIDATE_TYPE_RELAYED) {
1221 nice_turn_socket_set_peer (component->selected_pair.local->sockptr,
1222 &component->selected_pair.remote->addr);
1225 if (component->tcp) {
1226 pseudo_tcp_socket_connect (component->tcp);
1227 pseudo_tcp_socket_notify_mtu (component->tcp, MAX_TCP_MTU);
1228 adjust_tcp_clock (agent, stream, component);
1229 } else if(agent->reliable) {
1230 nice_debug ("New selected pair received when pseudo tcp socket in error");
1231 return;
1234 lf_copy = g_strdup (local_foundation);
1235 rf_copy = g_strdup (remote_foundation);
1237 g_signal_emit (agent, signals[SIGNAL_NEW_SELECTED_PAIR], 0,
1238 stream_id, component_id, lf_copy, rf_copy);
1240 g_free (lf_copy);
1241 g_free (rf_copy);
1244 void agent_signal_new_candidate (NiceAgent *agent, NiceCandidate *candidate)
1246 g_signal_emit (agent, signals[SIGNAL_NEW_CANDIDATE], 0,
1247 candidate->stream_id,
1248 candidate->component_id,
1249 candidate->foundation);
1252 void agent_signal_new_remote_candidate (NiceAgent *agent, NiceCandidate *candidate)
1254 g_signal_emit (agent, signals[SIGNAL_NEW_REMOTE_CANDIDATE], 0,
1255 candidate->stream_id,
1256 candidate->component_id,
1257 candidate->foundation);
1260 void agent_signal_component_state_change (NiceAgent *agent, guint stream_id, guint component_id, NiceComponentState state)
1262 Component *component;
1263 Stream *stream;
1265 if (!agent_find_component (agent, stream_id, component_id,
1266 &stream, &component))
1267 return;
1269 if (agent->reliable && component->tcp == NULL &&
1270 state != NICE_COMPONENT_STATE_FAILED) {
1271 nice_debug ("Agent %p: not changing component state for s%d:%d to %d "
1272 "because pseudo tcp socket does not exist in reliable mode", agent,
1273 stream->id, component->id, state);
1274 return;
1277 if (component->state != state && state < NICE_COMPONENT_STATE_LAST) {
1278 nice_debug ("Agent %p : stream %u component %u STATE-CHANGE %u -> %u.", agent,
1279 stream_id, component_id, component->state, state);
1281 component->state = state;
1283 g_signal_emit (agent, signals[SIGNAL_COMPONENT_STATE_CHANGED], 0,
1284 stream_id, component_id, state);
1288 guint64
1289 agent_candidate_pair_priority (NiceAgent *agent, NiceCandidate *local, NiceCandidate *remote)
1291 if (agent->controlling_mode)
1292 return nice_candidate_pair_priority (local->priority, remote->priority);
1293 else
1294 return nice_candidate_pair_priority (remote->priority, local->priority);
1297 static gboolean
1298 priv_add_new_candidate_discovery_stun (NiceAgent *agent,
1299 NiceSocket *socket, NiceAddress server,
1300 Stream *stream, guint component_id)
1302 CandidateDiscovery *cdisco;
1303 GSList *modified_list;
1305 /* note: no need to check for redundant candidates, as this is
1306 * done later on in the process */
1308 cdisco = g_slice_new0 (CandidateDiscovery);
1309 if (cdisco) {
1310 modified_list = g_slist_append (agent->discovery_list, cdisco);
1312 if (modified_list) {
1313 cdisco->type = NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE;
1314 cdisco->nicesock = socket;
1315 cdisco->server = server;
1316 cdisco->stream = stream;
1317 cdisco->component = stream_find_component_by_id (stream, component_id);
1318 cdisco->agent = agent;
1319 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1320 STUN_COMPATIBILITY_RFC3489, 0);
1322 nice_debug ("Agent %p : Adding new srv-rflx candidate discovery %p\n",
1323 agent, cdisco);
1324 agent->discovery_list = modified_list;
1325 ++agent->discovery_unsched_items;
1328 return TRUE;
1331 return FALSE;
1334 static gboolean
1335 priv_add_new_candidate_discovery_turn (NiceAgent *agent,
1336 NiceSocket *socket, TurnServer *turn,
1337 Stream *stream, guint component_id)
1339 CandidateDiscovery *cdisco;
1340 GSList *modified_list;
1341 GSList *socket_modified_list;
1343 /* note: no need to check for redundant candidates, as this is
1344 * done later on in the process */
1346 cdisco = g_slice_new0 (CandidateDiscovery);
1347 if (cdisco) {
1348 modified_list = g_slist_append (agent->discovery_list, cdisco);
1350 if (modified_list) {
1351 Component *component = stream_find_component_by_id (stream, component_id);
1353 cdisco->type = NICE_CANDIDATE_TYPE_RELAYED;
1355 if (turn->type == NICE_RELAY_TYPE_TURN_UDP) {
1356 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
1357 NiceAddress addr = socket->addr;
1358 NiceSocket *new_socket;
1359 nice_address_set_port (&addr, 0);
1361 new_socket = nice_udp_bsd_socket_new (&addr);
1362 if (new_socket) {
1363 _priv_set_socket_tos (agent, new_socket, stream->tos);
1364 agent_attach_stream_component_socket (agent, stream,
1365 component, new_socket);
1366 socket_modified_list = g_slist_append (component->sockets, new_socket);
1367 if (socket_modified_list) {
1368 /* success: store a pointer to the sockaddr */
1369 component->sockets = socket_modified_list;
1370 socket = new_socket;
1371 } else {
1372 nice_socket_free (new_socket);
1376 cdisco->nicesock = socket;
1377 } else {
1378 NiceAddress proxy_server;
1379 socket = NULL;
1381 if (agent->proxy_type != NICE_PROXY_TYPE_NONE &&
1382 agent->proxy_ip != NULL &&
1383 nice_address_set_from_string (&proxy_server, agent->proxy_ip)) {
1384 nice_address_set_port (&proxy_server, agent->proxy_port);
1385 socket = nice_tcp_bsd_socket_new (agent, component->ctx, &proxy_server);
1387 if (socket) {
1388 _priv_set_socket_tos (agent, socket, stream->tos);
1389 if (agent->proxy_type == NICE_PROXY_TYPE_SOCKS5) {
1390 socket = nice_socks5_socket_new (socket, &turn->server,
1391 agent->proxy_username, agent->proxy_password);
1392 } else if (agent->proxy_type == NICE_PROXY_TYPE_HTTP){
1393 socket = nice_http_socket_new (socket, &turn->server,
1394 agent->proxy_username, agent->proxy_password);
1395 } else {
1396 nice_socket_free (socket);
1397 socket = NULL;
1402 if (socket == NULL) {
1403 socket = nice_tcp_bsd_socket_new (agent, component->ctx, &turn->server);
1404 _priv_set_socket_tos (agent, socket, stream->tos);
1406 if (turn->type == NICE_RELAY_TYPE_TURN_TLS &&
1407 agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
1408 socket = nice_pseudossl_socket_new (agent, socket);
1410 cdisco->nicesock = nice_tcp_turn_socket_new (agent, socket,
1411 agent_to_turn_socket_compatibility (agent));
1413 if (!cdisco->nicesock) {
1414 agent->discovery_list = g_slist_remove (modified_list, cdisco);
1415 g_slice_free (CandidateDiscovery, cdisco);
1416 return FALSE;
1419 agent_attach_stream_component_socket (agent, stream,
1420 component, cdisco->nicesock);
1421 socket_modified_list = g_slist_append (component->sockets, cdisco->nicesock);
1422 if (socket_modified_list) {
1423 /* success: store a pointer to the sockaddr */
1424 component->sockets = socket_modified_list;
1427 cdisco->turn = turn;
1428 cdisco->server = turn->server;
1430 cdisco->stream = stream;
1431 cdisco->component = stream_find_component_by_id (stream, component_id);
1432 cdisco->agent = agent;
1434 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
1435 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1436 STUN_COMPATIBILITY_RFC3489,
1437 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
1438 STUN_AGENT_USAGE_IGNORE_CREDENTIALS);
1439 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
1440 agent->compatibility == NICE_COMPATIBILITY_WLM2009) {
1441 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1442 STUN_COMPATIBILITY_RFC3489,
1443 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS);
1444 } else {
1445 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
1446 STUN_COMPATIBILITY_RFC5389,
1447 STUN_AGENT_USAGE_ADD_SOFTWARE |
1448 STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS);
1450 stun_agent_set_software (&cdisco->stun_agent, agent->software_attribute);
1452 nice_debug ("Agent %p : Adding new relay-rflx candidate discovery %p\n",
1453 agent, cdisco);
1454 agent->discovery_list = modified_list;
1455 ++agent->discovery_unsched_items;
1458 return TRUE;
1461 return FALSE;
1464 NICEAPI_EXPORT guint
1465 nice_agent_add_stream (
1466 NiceAgent *agent,
1467 guint n_components)
1469 Stream *stream;
1470 GSList *modified_list = NULL;
1471 guint ret = 0;
1472 guint i;
1474 agent_lock();
1475 stream = stream_new (n_components);
1476 if (stream) {
1477 modified_list = g_slist_append (agent->streams, stream);
1478 if (modified_list) {
1479 stream->id = agent->next_stream_id++;
1480 nice_debug ("Agent %p : allocating stream id %u (%p)", agent, stream->id, stream);
1481 if (agent->reliable) {
1482 nice_debug ("Agent %p : reliable stream", agent);
1483 for (i = 0; i < n_components; i++) {
1484 Component *component = stream_find_component_by_id (stream, i + 1);
1485 if (component) {
1486 TcpUserData *data = g_slice_new0 (TcpUserData);
1487 PseudoTcpCallbacks tcp_callbacks = {data,
1488 pseudo_tcp_socket_opened,
1489 pseudo_tcp_socket_readable,
1490 pseudo_tcp_socket_writable,
1491 pseudo_tcp_socket_closed,
1492 pseudo_tcp_socket_write_packet};
1493 data->agent = agent;
1494 data->stream = stream;
1495 data->component = component;
1496 component->tcp_data = data;
1497 component->tcp = pseudo_tcp_socket_new (0, &tcp_callbacks);
1498 adjust_tcp_clock (agent, stream, component);
1499 nice_debug ("Agent %p: Create Pseudo Tcp Socket for component %d",
1500 agent, i+1);
1501 } else {
1502 nice_debug ("Agent %p: couldn't find component %d", agent, i+1);
1507 stream_initialize_credentials (stream, agent->rng);
1509 agent->streams = modified_list;
1511 else
1512 stream_free (stream);
1515 ret = stream->id;
1517 agent_unlock();
1518 return ret;
1522 NICEAPI_EXPORT gboolean
1523 nice_agent_set_relay_info(NiceAgent *agent,
1524 guint stream_id, guint component_id,
1525 const gchar *server_ip, guint server_port,
1526 const gchar *username, const gchar *password,
1527 NiceRelayType type)
1530 Component *component = NULL;
1532 g_return_val_if_fail (server_ip, FALSE);
1533 g_return_val_if_fail (server_port, FALSE);
1534 g_return_val_if_fail (username, FALSE);
1535 g_return_val_if_fail (password, FALSE);
1536 g_return_val_if_fail (type <= NICE_PROXY_TYPE_LAST, FALSE);
1538 agent_lock();
1540 if (agent_find_component (agent, stream_id, component_id, NULL, &component)) {
1541 TurnServer *turn = g_slice_new0 (TurnServer);
1542 nice_address_init (&turn->server);
1544 if (nice_address_set_from_string (&turn->server, server_ip)) {
1545 nice_address_set_port (&turn->server, server_port);
1546 } else {
1547 g_slice_free (TurnServer, turn);
1548 agent_unlock();
1549 return FALSE;
1553 turn->username = g_strdup (username);
1554 turn->password = g_strdup (password);
1555 turn->type = type;
1557 nice_debug ("Agent %p: added relay server [%s]:%d of type %d", agent,
1558 server_ip, server_port, type);
1560 component->turn_servers = g_list_append (component->turn_servers, turn);
1563 agent_unlock();
1564 return TRUE;
1567 #ifdef HAVE_GUPNP
1569 static gboolean priv_upnp_timeout_cb (gpointer user_data)
1571 NiceAgent *agent = (NiceAgent*)user_data;
1572 GSList *i;
1574 agent_lock();
1576 if (g_source_is_destroyed (g_main_current_source ())) {
1577 agent_unlock ();
1578 return FALSE;
1581 nice_debug ("Agent %p : UPnP port mapping timed out", agent);
1583 for (i = agent->upnp_mapping; i; i = i->next) {
1584 NiceAddress *a = i->data;
1585 nice_address_free (a);
1587 g_slist_free (agent->upnp_mapping);
1588 agent->upnp_mapping = NULL;
1590 if (agent->upnp_timer_source != NULL) {
1591 g_source_destroy (agent->upnp_timer_source);
1592 g_source_unref (agent->upnp_timer_source);
1593 agent->upnp_timer_source = NULL;
1596 agent_gathering_done (agent);
1598 agent_unlock();
1599 return FALSE;
1602 static void _upnp_mapped_external_port (GUPnPSimpleIgd *self, gchar *proto,
1603 gchar *external_ip, gchar *replaces_external_ip, guint external_port,
1604 gchar *local_ip, guint local_port, gchar *description, gpointer user_data)
1606 NiceAgent *agent = (NiceAgent*)user_data;
1607 NiceAddress localaddr;
1608 NiceAddress externaddr;
1610 GSList *i, *j, *k;
1612 agent_lock();
1614 nice_debug ("Agent %p : Sucessfully mapped %s:%d to %s:%d", agent, local_ip,
1615 local_port, external_ip, external_port);
1617 if (!nice_address_set_from_string (&localaddr, local_ip))
1618 goto end;
1619 nice_address_set_port (&localaddr, local_port);
1621 for (i = agent->upnp_mapping; i; i = i->next) {
1622 NiceAddress *addr = i->data;
1623 if (nice_address_equal (&localaddr, addr)) {
1624 agent->upnp_mapping = g_slist_remove (agent->upnp_mapping, addr);
1625 nice_address_free (addr);
1626 break;
1630 if (!nice_address_set_from_string (&externaddr, external_ip))
1631 goto end;
1632 nice_address_set_port (&externaddr, external_port);
1634 for (i = agent->streams; i; i = i->next) {
1635 Stream *stream = i->data;
1636 for (j = stream->components; j; j = j->next) {
1637 Component *component = j->data;
1638 for (k = component->local_candidates; k; k = k->next) {
1639 NiceCandidate *local_candidate = k->data;
1641 if (nice_address_equal (&localaddr, &local_candidate->base_addr)) {
1642 discovery_add_server_reflexive_candidate (
1643 agent,
1644 stream->id,
1645 component->id,
1646 &externaddr,
1647 local_candidate->sockptr);
1648 goto end;
1654 end:
1655 if (g_slist_length (agent->upnp_mapping)) {
1656 if (agent->upnp_timer_source != NULL) {
1657 g_source_destroy (agent->upnp_timer_source);
1658 g_source_unref (agent->upnp_timer_source);
1659 agent->upnp_timer_source = NULL;
1661 agent_gathering_done (agent);
1664 agent_unlock();
1667 static void _upnp_error_mapping_port (GUPnPSimpleIgd *self, GError *error,
1668 gchar *proto, guint external_port, gchar *local_ip, guint local_port,
1669 gchar *description, gpointer user_data)
1671 NiceAgent *agent = (NiceAgent*)user_data;
1672 NiceAddress localaddr;
1673 GSList *i;
1675 agent_lock();
1677 nice_debug ("Agent %p : Error mapping %s:%d to %d (%d) : %s", agent, local_ip,
1678 local_port, external_port, error->domain, error->message);
1679 if (nice_address_set_from_string (&localaddr, local_ip)) {
1680 nice_address_set_port (&localaddr, local_port);
1682 for (i = agent->upnp_mapping; i; i = i->next) {
1683 NiceAddress *addr = i->data;
1684 if (nice_address_equal (&localaddr, addr)) {
1685 agent->upnp_mapping = g_slist_remove (agent->upnp_mapping, addr);
1686 nice_address_free (addr);
1687 break;
1691 if (g_slist_length (agent->upnp_mapping)) {
1692 if (agent->upnp_timer_source != NULL) {
1693 g_source_destroy (agent->upnp_timer_source);
1694 g_source_unref (agent->upnp_timer_source);
1695 agent->upnp_timer_source = NULL;
1697 agent_gathering_done (agent);
1701 agent_unlock();
1704 #endif
1706 NICEAPI_EXPORT void
1707 nice_agent_gather_candidates (
1708 NiceAgent *agent,
1709 guint stream_id)
1711 guint n;
1712 GSList *i;
1713 Stream *stream;
1715 agent_lock();
1717 stream = agent_find_stream (agent, stream_id);
1718 if (stream == NULL) {
1719 goto done;
1722 nice_debug ("Agent %p : In %s mode, starting candidate gathering.", agent,
1723 agent->full_mode ? "ICE-FULL" : "ICE-LITE");
1725 #ifdef HAVE_GUPNP
1726 priv_free_upnp (agent);
1728 if (agent->upnp_enabled) {
1729 agent->upnp = gupnp_simple_igd_thread_new ();
1731 agent->upnp_timer_source = agent_timeout_add_with_context (agent,
1732 agent->upnp_timeout, priv_upnp_timeout_cb, agent);
1734 if (agent->upnp) {
1735 g_signal_connect (agent->upnp, "mapped-external-port",
1736 G_CALLBACK (_upnp_mapped_external_port), agent);
1737 g_signal_connect (agent->upnp, "error-mapping-port",
1738 G_CALLBACK (_upnp_error_mapping_port), agent);
1739 } else {
1740 nice_debug ("Agent %p : Error creating UPnP Simple IGD agent", agent);
1742 } else {
1743 nice_debug ("Agent %p : UPnP property Disabled", agent);
1745 #else
1746 nice_debug ("Agent %p : libnice compiled without UPnP support", agent);
1747 #endif
1749 /* if no local addresses added, generate them ourselves */
1750 if (agent->local_addresses == NULL) {
1751 GList *addresses = nice_interfaces_get_local_ips (FALSE);
1752 GList *item;
1754 for (item = addresses; item; item = g_list_next (item)) {
1755 NiceAddress *addr = nice_address_new ();
1757 if (nice_address_set_from_string (addr, item->data)) {
1758 nice_agent_add_local_address (agent, addr);
1760 nice_address_free (addr);
1763 g_list_foreach (addresses, (GFunc) g_free, NULL);
1764 g_list_free (addresses);
1767 /* generate a local host candidate for each local address */
1768 for (i = agent->local_addresses; i; i = i->next){
1769 NiceAddress *addr = i->data;
1770 NiceCandidate *host_candidate;
1772 #ifdef HAVE_GUPNP
1773 gchar local_ip[NICE_ADDRESS_STRING_LEN];
1774 nice_address_to_string (addr, local_ip);
1775 #endif
1777 for (n = 0; n < stream->n_components; n++) {
1778 Component *component = stream_find_component_by_id (stream, n + 1);
1780 if (agent->reliable && component->tcp == NULL) {
1781 nice_debug ("Agent %p: not gathering candidates for s%d:%d because "
1782 "pseudo tcp socket does not exist in reliable mode", agent,
1783 stream->id, component->id);
1784 continue;
1787 host_candidate = discovery_add_local_host_candidate (agent, stream->id,
1788 n + 1, addr);
1790 if (!host_candidate) {
1791 g_error ("No host candidate??");
1792 break;
1795 #ifdef HAVE_GUPNP
1796 if (agent->upnp_enabled) {
1797 NiceAddress *addr = nice_address_dup (&host_candidate->base_addr);
1798 nice_debug ("Agent %p: Adding UPnP port %s:%d", agent, local_ip,
1799 nice_address_get_port (&host_candidate->base_addr));
1800 gupnp_simple_igd_add_port (GUPNP_SIMPLE_IGD (agent->upnp), "UDP",
1801 0, local_ip, nice_address_get_port (&host_candidate->base_addr),
1802 0, PACKAGE_STRING);
1803 agent->upnp_mapping = g_slist_prepend (agent->upnp_mapping, addr);
1805 #endif
1807 if (agent->full_mode &&
1808 agent->stun_server_ip) {
1809 NiceAddress stun_server;
1810 if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
1811 gboolean res;
1812 nice_address_set_port (&stun_server, agent->stun_server_port);
1814 res =
1815 priv_add_new_candidate_discovery_stun (agent,
1816 host_candidate->sockptr,
1817 stun_server,
1818 stream,
1819 n + 1);
1821 if (res != TRUE) {
1822 /* note: memory allocation failure, return error */
1823 g_error ("Memory allocation failure?");
1828 if (agent->full_mode && component) {
1829 GList *item;
1831 for (item = component->turn_servers; item; item = item->next) {
1832 TurnServer *turn = item->data;
1834 gboolean res =
1835 priv_add_new_candidate_discovery_turn (agent,
1836 host_candidate->sockptr,
1837 turn,
1838 stream,
1839 n + 1);
1841 if (res != TRUE) {
1842 /* note: memory allocation failure, return error */
1843 g_error ("Memory allocation failure?");
1850 stream->gathering = TRUE;
1853 /* note: no async discoveries pending, signal that we are ready */
1854 if (agent->discovery_unsched_items == 0) {
1855 nice_debug ("Agent %p: Candidate gathering FINISHED, no scheduled items.",
1856 agent);
1857 agent_gathering_done (agent);
1858 } else {
1859 g_assert (agent->discovery_list);
1860 discovery_schedule (agent);
1863 done:
1865 agent_unlock();
1868 static void priv_free_upnp (NiceAgent *agent)
1870 #ifdef HAVE_GUPNP
1871 GSList *i;
1873 if (agent->upnp) {
1874 g_object_unref (agent->upnp);
1875 agent->upnp = NULL;
1878 for (i = agent->upnp_mapping; i; i = i->next) {
1879 NiceAddress *a = i->data;
1880 nice_address_free (a);
1882 g_slist_free (agent->upnp_mapping);
1883 agent->upnp_mapping = NULL;
1885 if (agent->upnp_timer_source != NULL) {
1886 g_source_destroy (agent->upnp_timer_source);
1887 g_source_unref (agent->upnp_timer_source);
1888 agent->upnp_timer_source = NULL;
1890 #endif
1893 static void priv_remove_keepalive_timer (NiceAgent *agent)
1895 if (agent->keepalive_timer_source != NULL) {
1896 g_source_destroy (agent->keepalive_timer_source);
1897 g_source_unref (agent->keepalive_timer_source);
1898 agent->keepalive_timer_source = NULL;
1902 NICEAPI_EXPORT void
1903 nice_agent_remove_stream (
1904 NiceAgent *agent,
1905 guint stream_id)
1907 /* note that streams/candidates can be in use by other threads */
1909 Stream *stream;
1911 agent_lock();
1912 stream = agent_find_stream (agent, stream_id);
1914 if (!stream) {
1915 goto done;
1918 /* note: remove items with matching stream_ids from both lists */
1919 conn_check_prune_stream (agent, stream);
1920 discovery_prune_stream (agent, stream_id);
1921 refresh_prune_stream (agent, stream_id);
1923 /* remove the stream itself */
1924 agent->streams = g_slist_remove (agent->streams, stream);
1925 stream_free (stream);
1927 if (!agent->streams)
1928 priv_remove_keepalive_timer (agent);
1930 done:
1931 agent_unlock();
1934 NICEAPI_EXPORT gboolean
1935 nice_agent_add_local_address (NiceAgent *agent, NiceAddress *addr)
1937 NiceAddress *dup;
1938 GSList *modified_list;
1939 gboolean ret = FALSE;
1941 agent_lock();
1943 dup = nice_address_dup (addr);
1944 nice_address_set_port (dup, 0);
1945 modified_list = g_slist_append (agent->local_addresses, dup);
1946 if (modified_list) {
1947 agent->local_addresses = modified_list;
1949 ret = TRUE;
1950 goto done;
1953 done:
1954 agent_unlock();
1955 return ret;
1958 static gboolean priv_add_remote_candidate (
1959 NiceAgent *agent,
1960 guint stream_id,
1961 guint component_id,
1962 NiceCandidateType type,
1963 const NiceAddress *addr,
1964 const NiceAddress *base_addr,
1965 NiceCandidateTransport transport,
1966 guint32 priority,
1967 const gchar *username,
1968 const gchar *password,
1969 const gchar *foundation)
1971 Component *component;
1972 NiceCandidate *candidate;
1973 gboolean error_flag = FALSE;
1975 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
1976 return FALSE;
1978 /* step: check whether the candidate already exists */
1979 candidate = component_find_remote_candidate(component, addr, transport);
1980 if (candidate) {
1982 gchar tmpbuf[INET6_ADDRSTRLEN];
1983 nice_address_to_string (addr, tmpbuf);
1984 nice_debug ("Agent %p : Updating existing remote candidate with addr [%s]:%u"
1985 " for s%d/c%d. U/P '%s'/'%s' prio: %u", agent, tmpbuf,
1986 nice_address_get_port (addr), stream_id, component_id,
1987 username, password, priority);
1989 /* case 1: an existing candidate, update the attributes */
1990 candidate->type = type;
1991 if (base_addr)
1992 candidate->base_addr = *base_addr;
1993 candidate->priority = priority;
1994 if (foundation)
1995 g_strlcpy(candidate->foundation, foundation,
1996 NICE_CANDIDATE_MAX_FOUNDATION);
1997 /* note: username and password must remain the same during
1998 * a session; see sect 9.1.2 in ICE ID-19 */
2000 /* note: however, the user/pass in ID-19 is global, if the user/pass
2001 * are set in the candidate here, it means they need to be updated...
2002 * this is essential to overcome a race condition where we might receive
2003 * a valid binding request from a valid candidate that wasn't yet added to
2004 * our list of candidates.. this 'update' will make the peer-rflx a
2005 * server-rflx/host candidate again and restore that user/pass it needed
2006 * to have in the first place */
2007 if (username) {
2008 g_free (candidate->username);
2009 candidate->username = g_strdup (username);
2011 if (password) {
2012 g_free (candidate->password);
2013 candidate->password = g_strdup (password);
2015 if (conn_check_add_for_candidate (agent, stream_id, component, candidate) < 0)
2016 error_flag = TRUE;
2018 else {
2019 /* case 2: add a new candidate */
2021 candidate = nice_candidate_new (type);
2022 if (candidate) {
2023 GSList *modified_list = g_slist_append (component->remote_candidates, candidate);
2024 if (modified_list) {
2025 component->remote_candidates = modified_list;
2027 candidate->stream_id = stream_id;
2028 candidate->component_id = component_id;
2030 candidate->type = type;
2031 if (addr)
2032 candidate->addr = *addr;
2034 gchar tmpbuf[INET6_ADDRSTRLEN] = {0};
2035 if(addr)
2036 nice_address_to_string (addr, tmpbuf);
2037 nice_debug ("Agent %p : Adding remote candidate with addr [%s]:%u"
2038 " for s%d/c%d. U/P '%s'/'%s' prio: %u", agent, tmpbuf,
2039 addr? nice_address_get_port (addr) : 0, stream_id, component_id,
2040 username, password, priority);
2043 if (base_addr)
2044 candidate->base_addr = *base_addr;
2046 candidate->transport = transport;
2047 candidate->priority = priority;
2048 candidate->username = g_strdup (username);
2049 candidate->password = g_strdup (password);
2051 if (foundation)
2052 g_strlcpy (candidate->foundation, foundation,
2053 NICE_CANDIDATE_MAX_FOUNDATION);
2055 if (conn_check_add_for_candidate (agent, stream_id, component, candidate) < 0)
2056 error_flag = TRUE;
2058 else /* memory alloc error: list insert */
2059 error_flag = TRUE;
2061 else /* memory alloc error: candidate creation */
2062 error_flag = TRUE;
2065 if (error_flag) {
2066 if (candidate)
2067 nice_candidate_free (candidate);
2068 return FALSE;
2071 return TRUE;
2074 NICEAPI_EXPORT gboolean
2075 nice_agent_set_remote_credentials (
2076 NiceAgent *agent,
2077 guint stream_id,
2078 const gchar *ufrag, const gchar *pwd)
2080 Stream *stream;
2081 gboolean ret = FALSE;
2083 agent_lock();
2085 stream = agent_find_stream (agent, stream_id);
2086 /* note: oddly enough, ufrag and pwd can be empty strings */
2087 if (stream && ufrag && pwd) {
2089 g_strlcpy (stream->remote_ufrag, ufrag, NICE_STREAM_MAX_UFRAG);
2090 g_strlcpy (stream->remote_password, pwd, NICE_STREAM_MAX_PWD);
2092 ret = TRUE;
2093 goto done;
2096 done:
2097 agent_unlock();
2098 return ret;
2102 NICEAPI_EXPORT gboolean
2103 nice_agent_get_local_credentials (
2104 NiceAgent *agent,
2105 guint stream_id,
2106 gchar **ufrag, gchar **pwd)
2108 Stream *stream;
2109 gboolean ret = TRUE;
2111 agent_lock();
2113 stream = agent_find_stream (agent, stream_id);
2114 if (stream == NULL) {
2115 goto done;
2118 if (!ufrag || !pwd) {
2119 goto done;
2122 *ufrag = g_strdup (stream->local_ufrag);
2123 *pwd = g_strdup (stream->local_password);
2124 ret = TRUE;
2126 done:
2128 agent_unlock();
2129 return ret;
2132 NICEAPI_EXPORT int
2133 nice_agent_set_remote_candidates (NiceAgent *agent, guint stream_id, guint component_id, const GSList *candidates)
2135 const GSList *i;
2136 int added = 0;
2137 Stream *stream;
2138 Component *component;
2140 nice_debug ("Agent %p: set_remote_candidates %d %d", agent, stream_id, component_id);
2142 agent_lock();
2144 if (!agent_find_component (agent, stream_id, component_id,
2145 &stream, &component)) {
2146 g_warning ("Could not find component %u in stream %u", component_id,
2147 stream_id);
2148 added = -1;
2149 goto done;
2152 if (agent->discovery_unsched_items > 0 || stream->gathering) {
2153 nice_debug ("Agent %p: Remote candidates refused for stream %d because "
2154 "we are still gathering our own candidates", agent, stream_id);
2155 added = -1;
2156 goto done;
2159 if (agent->reliable && component->tcp == NULL) {
2160 nice_debug ("Agent %p: not setting remote candidate for s%d:%d because "
2161 "pseudo tcp socket does not exist in reliable mode", agent,
2162 stream->id, component->id);
2163 goto done;
2166 for (i = candidates; i && added >= 0; i = i->next) {
2167 NiceCandidate *d = (NiceCandidate*) i->data;
2169 if (nice_address_is_valid (&d->addr) == TRUE) {
2170 gboolean res =
2171 priv_add_remote_candidate (agent,
2172 stream_id,
2173 component_id,
2174 d->type,
2175 &d->addr,
2176 &d->base_addr,
2177 d->transport,
2178 d->priority,
2179 d->username,
2180 d->password,
2181 d->foundation);
2182 if (res)
2183 ++added;
2187 conn_check_remote_candidates_set(agent);
2189 if (added > 0) {
2190 gboolean res = conn_check_schedule_next (agent);
2191 if (res != TRUE)
2192 nice_debug ("Agent %p : Warning: unable to schedule any conn checks!", agent);
2195 done:
2196 agent_unlock();
2197 return added;
2201 static gint
2202 _nice_agent_recv (
2203 NiceAgent *agent,
2204 Stream *stream,
2205 Component *component,
2206 NiceSocket *socket,
2207 guint buf_len,
2208 gchar *buf)
2210 NiceAddress from;
2211 gint len;
2212 GList *item;
2214 len = nice_socket_recv (socket, &from, buf_len, buf);
2216 if (len <= 0)
2217 return len;
2219 #ifndef NDEBUG
2220 if (len > 0) {
2221 gchar tmpbuf[INET6_ADDRSTRLEN];
2222 nice_address_to_string (&from, tmpbuf);
2223 nice_debug ("Agent %p : Packet received on local socket %u from [%s]:%u (%u octets).", agent,
2224 socket->fileno, tmpbuf, nice_address_get_port (&from), len);
2226 #endif
2229 if ((guint)len > buf_len)
2231 /* buffer is not big enough to accept this packet */
2232 /* XXX: test this case */
2233 return 0;
2236 for (item = component->turn_servers; item; item = g_list_next (item)) {
2237 TurnServer *turn = item->data;
2238 if (nice_address_equal (&from, &turn->server)) {
2239 GSList * i = NULL;
2240 #ifndef NDEBUG
2241 nice_debug ("Agent %p : Packet received from TURN server candidate.",
2242 agent);
2243 #endif
2244 for (i = component->local_candidates; i; i = i->next) {
2245 NiceCandidate *cand = i->data;
2246 if (cand->type == NICE_CANDIDATE_TYPE_RELAYED &&
2247 cand->stream_id == stream->id &&
2248 cand->component_id == component->id) {
2249 len = nice_turn_socket_parse_recv (cand->sockptr, &socket,
2250 &from, len, buf, &from, buf, len);
2253 break;
2257 agent->media_after_tick = TRUE;
2259 if (stun_message_validate_buffer_length ((uint8_t *) buf, (size_t) len) != len)
2260 /* If the retval is no 0, its not a valid stun packet, probably data */
2261 return len;
2264 if (conn_check_handle_inbound_stun (agent, stream, component, socket,
2265 &from, buf, len))
2266 /* handled STUN message*/
2267 return 0;
2269 /* unhandled STUN, pass to client */
2270 return len;
2274 NICEAPI_EXPORT gint
2275 nice_agent_send (
2276 NiceAgent *agent,
2277 guint stream_id,
2278 guint component_id,
2279 guint len,
2280 const gchar *buf)
2282 Stream *stream;
2283 Component *component;
2284 gint ret = -1;
2286 agent_lock();
2288 if (!agent_find_component (agent, stream_id, component_id,
2289 &stream, &component)) {
2290 goto done;
2293 if (component->tcp != NULL) {
2294 ret = pseudo_tcp_socket_send (component->tcp, buf, len);
2295 adjust_tcp_clock (agent, stream, component);
2297 if (ret == -1 &&
2298 pseudo_tcp_socket_get_error (component->tcp) != EWOULDBLOCK) {
2301 /* In case of -1, the error is either EWOULDBLOCK or ENOTCONN, which both
2302 need the user to wait for the reliable-transport-writable signal */
2303 } else if(agent->reliable) {
2304 nice_debug ("Trying to send on a pseudo tcp FAILED component");
2305 goto done;
2306 } else if (component->selected_pair.local != NULL) {
2307 NiceSocket *sock;
2308 NiceAddress *addr;
2310 #ifndef NDEBUG
2311 gchar tmpbuf[INET6_ADDRSTRLEN];
2312 nice_address_to_string (&component->selected_pair.remote->addr, tmpbuf);
2314 nice_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", agent, stream_id, component_id,
2315 len, tmpbuf,
2316 nice_address_get_port (&component->selected_pair.remote->addr));
2317 #endif
2319 sock = component->selected_pair.local->sockptr;
2320 addr = &component->selected_pair.remote->addr;
2321 if (nice_socket_send (sock, addr, len, buf)) {
2322 ret = len;
2324 goto done;
2327 done:
2328 agent_unlock();
2329 return ret;
2333 NICEAPI_EXPORT GSList *
2334 nice_agent_get_local_candidates (
2335 NiceAgent *agent,
2336 guint stream_id,
2337 guint component_id)
2339 Component *component;
2340 GSList * ret = NULL;
2341 GSList * item = NULL;
2343 agent_lock();
2345 if (!agent_find_component (agent, stream_id, component_id, NULL, &component)) {
2346 goto done;
2349 for (item = component->local_candidates; item; item = item->next)
2350 ret = g_slist_append (ret, nice_candidate_copy (item->data));
2352 done:
2353 agent_unlock();
2354 return ret;
2358 NICEAPI_EXPORT GSList *
2359 nice_agent_get_remote_candidates (
2360 NiceAgent *agent,
2361 guint stream_id,
2362 guint component_id)
2364 Component *component;
2365 GSList *ret = NULL, *item = NULL;
2367 agent_lock();
2368 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
2370 goto done;
2373 for (item = component->remote_candidates; item; item = item->next)
2374 ret = g_slist_append (ret, nice_candidate_copy (item->data));
2376 done:
2377 agent_unlock();
2378 return ret;
2382 gboolean
2383 nice_agent_restart (
2384 NiceAgent *agent)
2386 GSList *i;
2387 gboolean res = TRUE;
2389 agent_lock();
2391 /* step: clean up all connectivity checks */
2392 conn_check_free (agent);
2394 /* step: regenerate tie-breaker value */
2395 priv_generate_tie_breaker (agent);
2397 for (i = agent->streams; i && res; i = i->next) {
2398 Stream *stream = i->data;
2400 /* step: reset local credentials for the stream and
2401 * clean up the list of remote candidates */
2402 res = stream_restart (stream, agent->rng);
2405 agent_unlock();
2406 return res;
2410 static void
2411 nice_agent_dispose (GObject *object)
2413 GSList *i;
2414 NiceAgent *agent = NICE_AGENT (object);
2416 /* step: free resources for the binding discovery timers */
2417 discovery_free (agent);
2418 g_assert (agent->discovery_list == NULL);
2419 refresh_free (agent);
2420 g_assert (agent->refresh_list == NULL);
2422 /* step: free resources for the connectivity check timers */
2423 conn_check_free (agent);
2425 priv_remove_keepalive_timer (agent);
2427 for (i = agent->local_addresses; i; i = i->next)
2429 NiceAddress *a = i->data;
2431 nice_address_free (a);
2434 g_slist_free (agent->local_addresses);
2435 agent->local_addresses = NULL;
2437 for (i = agent->streams; i; i = i->next)
2439 Stream *s = i->data;
2441 stream_free (s);
2444 g_slist_free (agent->streams);
2445 agent->streams = NULL;
2447 g_free (agent->stun_server_ip);
2448 agent->stun_server_ip = NULL;
2450 nice_rng_free (agent->rng);
2451 agent->rng = NULL;
2453 priv_free_upnp (agent);
2455 g_free (agent->software_attribute);
2456 agent->software_attribute = NULL;
2458 if (agent->main_context != NULL)
2459 g_main_context_unref (agent->main_context);
2460 agent->main_context = NULL;
2462 if (G_OBJECT_CLASS (nice_agent_parent_class)->dispose)
2463 G_OBJECT_CLASS (nice_agent_parent_class)->dispose (object);
2468 typedef struct _IOCtx IOCtx;
2470 struct _IOCtx
2472 GIOChannel *channel;
2473 GSource *source;
2474 NiceAgent *agent;
2475 Stream *stream;
2476 Component *component;
2477 NiceSocket *socket;
2481 static IOCtx *
2482 io_ctx_new (
2483 NiceAgent *agent,
2484 Stream *stream,
2485 Component *component,
2486 NiceSocket *socket,
2487 GIOChannel *channel,
2488 GSource *source)
2490 IOCtx *ctx;
2492 ctx = g_slice_new0 (IOCtx);
2493 if (ctx) {
2494 ctx->agent = agent;
2495 ctx->stream = stream;
2496 ctx->component = component;
2497 ctx->socket = socket;
2498 ctx->channel = channel;
2499 ctx->source = source;
2501 return ctx;
2505 static void
2506 io_ctx_free (IOCtx *ctx)
2508 g_io_channel_unref (ctx->channel);
2509 g_slice_free (IOCtx, ctx);
2512 static gboolean
2513 nice_agent_g_source_cb (
2514 GIOChannel *io,
2515 G_GNUC_UNUSED
2516 GIOCondition condition,
2517 gpointer data)
2519 /* return value is whether to keep the source */
2521 IOCtx *ctx = data;
2522 NiceAgent *agent = ctx->agent;
2523 Stream *stream = ctx->stream;
2524 Component *component = ctx->component;
2525 gchar buf[MAX_BUFFER_SIZE];
2526 gint len;
2528 agent_lock();
2530 if (g_source_is_destroyed (g_main_current_source ())) {
2531 agent_unlock ();
2532 return FALSE;
2535 /* note: dear compiler, these are for you: */
2536 (void)io;
2538 len = _nice_agent_recv (agent, stream, component, ctx->socket,
2539 MAX_BUFFER_SIZE, buf);
2541 if (len > 0 && component->tcp) {
2542 g_object_add_weak_pointer (G_OBJECT (agent), (gpointer *)&agent);
2543 pseudo_tcp_socket_notify_packet (component->tcp, buf, len);
2544 if (agent) {
2545 adjust_tcp_clock (agent, stream, component);
2546 g_object_remove_weak_pointer (G_OBJECT (agent), (gpointer *)&agent);
2547 } else {
2548 nice_debug ("Our agent got destroyed in notify_packet!!");
2550 } else if(len > 0 && agent->reliable) {
2551 nice_debug ("Received data on a pseudo tcp FAILED component");
2552 } else if (len > 0 && component->g_source_io_cb) {
2553 gpointer data = component->data;
2554 gint sid = stream->id;
2555 gint cid = component->id;
2556 NiceAgentRecvFunc callback = component->g_source_io_cb;
2557 /* Unlock the agent before calling the callback */
2558 agent_unlock();
2559 callback (agent, sid, cid, len, buf, data);
2560 goto done;
2561 } else if (len < 0) {
2562 GSource *source = ctx->source;
2564 nice_debug ("Agent %p: _nice_agent_recv returned %d, errno (%d) : %s",
2565 agent, len, errno, g_strerror (errno));
2566 component->gsources = g_slist_remove (component->gsources, source);
2567 g_source_destroy (source);
2568 g_source_unref (source);
2569 /* We don't close the socket because it would be way too complicated to
2570 * take care of every path where the socket might still be used.. */
2571 nice_debug ("Agent %p: unable to recv from socket %p. Detaching", agent,
2572 ctx->socket);
2576 agent_unlock();
2578 done:
2580 return TRUE;
2584 * Attaches one socket handle to the main loop event context
2587 void
2588 agent_attach_stream_component_socket (NiceAgent *agent,
2589 Stream *stream,
2590 Component *component,
2591 NiceSocket *socket)
2593 GIOChannel *io;
2594 GSource *source;
2595 IOCtx *ctx;
2597 if (!component->ctx)
2598 return;
2600 io = g_io_channel_unix_new (socket->fileno);
2601 /* note: without G_IO_ERR the glib mainloop goes into
2602 * busyloop if errors are encountered */
2603 source = g_io_create_watch (io, G_IO_IN | G_IO_ERR);
2604 ctx = io_ctx_new (agent, stream, component, socket, io, source);
2605 g_source_set_callback (source, (GSourceFunc) nice_agent_g_source_cb,
2606 ctx, (GDestroyNotify) io_ctx_free);
2607 nice_debug ("Agent %p : Attach source %p (stream %u).", agent, source, stream->id);
2608 g_source_attach (source, component->ctx);
2609 component->gsources = g_slist_append (component->gsources, source);
2614 * Attaches socket handles of 'stream' to the main eventloop
2615 * context.
2618 static gboolean
2619 priv_attach_stream_component (NiceAgent *agent,
2620 Stream *stream,
2621 Component *component)
2623 GSList *i;
2625 for (i = component->sockets; i; i = i->next)
2626 agent_attach_stream_component_socket (agent, stream, component, i->data);
2628 return TRUE;
2632 * Detaches socket handles of 'stream' from the main eventloop
2633 * context.
2636 static void priv_detach_stream_component (Stream *stream, Component *component)
2638 GSList *i;
2640 for (i = component->gsources; i; i = i->next) {
2641 GSource *source = i->data;
2642 nice_debug ("Detach source %p (stream %u).", source, stream->id);
2643 g_source_destroy (source);
2644 g_source_unref (source);
2647 g_slist_free (component->gsources);
2648 component->gsources = NULL;
2651 NICEAPI_EXPORT gboolean
2652 nice_agent_attach_recv (
2653 NiceAgent *agent,
2654 guint stream_id,
2655 guint component_id,
2656 GMainContext *ctx,
2657 NiceAgentRecvFunc func,
2658 gpointer data)
2660 Component *component = NULL;
2661 Stream *stream = NULL;
2662 gboolean ret = FALSE;
2664 agent_lock();
2666 /* attach candidates */
2668 /* step: check that params specify an existing pair */
2669 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
2670 g_warning ("Could not find component %u in stream %u", component_id,
2671 stream_id);
2672 goto done;
2675 if (component->g_source_io_cb)
2676 priv_detach_stream_component (stream, component);
2678 ret = TRUE;
2680 if (func) {
2681 component->g_source_io_cb = func;
2682 component->data = data;
2683 component->ctx = ctx;
2685 priv_attach_stream_component (agent, stream, component);
2687 /* If we got detached, maybe our readable callback didn't finish reading
2688 * all available data in the pseudotcp, so we need to make sure we free
2689 * our recv window, so the readable callback can be triggered again on the
2690 * next incoming data.
2691 * but only do this if we know we're already readable, otherwise we might
2692 * trigger an error in the initial, pre-connection attach. */
2693 if (component->tcp && component->tcp_data && component->tcp_readable)
2694 pseudo_tcp_socket_readable (component->tcp, component->tcp_data);
2696 } else {
2697 component->g_source_io_cb = NULL;
2698 component->data = NULL;
2699 component->ctx = NULL;
2703 done:
2704 agent_unlock();
2705 return ret;
2708 NICEAPI_EXPORT gboolean
2709 nice_agent_set_selected_pair (
2710 NiceAgent *agent,
2711 guint stream_id,
2712 guint component_id,
2713 const gchar *lfoundation,
2714 const gchar *rfoundation)
2716 Component *component;
2717 Stream *stream;
2718 CandidatePair pair;
2719 gboolean ret = FALSE;
2721 agent_lock();
2723 /* step: check that params specify an existing pair */
2724 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
2725 goto done;
2728 if (!component_find_pair (component, agent, lfoundation, rfoundation, &pair)){
2729 goto done;
2732 /* step: stop connectivity checks (note: for the whole stream) */
2733 conn_check_prune_stream (agent, stream);
2735 if (agent->reliable && component->tcp == NULL) {
2736 nice_debug ("Agent %p: not setting selected pair for s%d:%d because "
2737 "pseudo tcp socket does not exist in reliable mode", agent,
2738 stream->id, component->id);
2739 goto done;
2742 /* step: change component state */
2743 agent_signal_component_state_change (agent, stream_id, component_id, NICE_COMPONENT_STATE_READY);
2745 /* step: set the selected pair */
2746 component_update_selected_pair (component, &pair);
2747 agent_signal_new_selected_pair (agent, stream_id, component_id, lfoundation, rfoundation);
2749 ret = TRUE;
2751 done:
2752 agent_unlock();
2753 return ret;
2757 GSource* agent_timeout_add_with_context (NiceAgent *agent, guint interval,
2758 GSourceFunc function, gpointer data)
2760 GSource *source;
2761 guint id;
2763 g_return_val_if_fail (function != NULL, 0);
2765 source = g_timeout_source_new (interval);
2767 g_source_set_callback (source, function, data, NULL);
2768 id = g_source_attach (source, agent->main_context);
2770 return source;
2774 NICEAPI_EXPORT gboolean
2775 nice_agent_set_selected_remote_candidate (
2776 NiceAgent *agent,
2777 guint stream_id,
2778 guint component_id,
2779 NiceCandidate *candidate)
2781 Component *component;
2782 Stream *stream;
2783 NiceCandidate *lcandidate = NULL;
2784 gboolean ret = FALSE;
2786 agent_lock();
2788 /* step: check if the component exists*/
2789 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
2790 goto done;
2793 /* step: stop connectivity checks (note: for the whole stream) */
2794 conn_check_prune_stream (agent, stream);
2797 if (agent->reliable && component->tcp == NULL) {
2798 nice_debug ("Agent %p: not setting selected remote candidate s%d:%d because "
2799 "pseudo tcp socket does not exist in reliable mode", agent,
2800 stream->id, component->id);
2801 goto done;
2804 /* step: set the selected pair */
2805 lcandidate = component_set_selected_remote_candidate (agent, component,
2806 candidate);
2807 if (!lcandidate)
2808 goto done;
2810 /* step: change component state */
2811 agent_signal_component_state_change (agent, stream_id, component_id, NICE_COMPONENT_STATE_READY);
2813 agent_signal_new_selected_pair (agent, stream_id, component_id,
2814 lcandidate->foundation,
2815 candidate->foundation);
2817 ret = TRUE;
2819 done:
2820 agent_unlock();
2821 return ret;
2824 void
2825 _priv_set_socket_tos (NiceAgent *agent, NiceSocket *sock, gint tos)
2827 if (setsockopt (sock->fileno, IPPROTO_IP,
2828 IP_TOS, &tos, sizeof (tos)) < 0) {
2829 nice_debug ("Agent %p: Could not set socket ToS", agent,
2830 g_strerror (errno));
2832 #ifdef IPV6_TCLASS
2833 if (setsockopt (sock->fileno, IPPROTO_IPV6,
2834 IPV6_TCLASS, &tos, sizeof (tos)) < 0) {
2835 nice_debug ("Agent %p: Could not set IPV6 socket ToS", agent,
2836 g_strerror (errno));
2838 #endif
2842 void nice_agent_set_stream_tos (NiceAgent *agent,
2843 guint stream_id, gint tos)
2846 GSList *i, *j, *k;
2848 agent_lock();
2850 for (i = agent->streams; i; i = i->next) {
2851 Stream *stream = i->data;
2852 if (stream->id == stream_id) {
2853 stream->tos = tos;
2854 for (j = stream->components; j; j = j->next) {
2855 Component *component = j->data;
2857 for (k = component->local_candidates; k; k = k->next) {
2858 NiceCandidate *local_candidate = k->data;
2859 _priv_set_socket_tos (agent, local_candidate->sockptr, tos);
2865 agent_unlock();
2868 void nice_agent_set_software (NiceAgent *agent, const gchar *software)
2870 agent_lock();
2872 g_free (agent->software_attribute);
2873 if (software)
2874 agent->software_attribute = g_strdup_printf ("%s/%s",
2875 software, PACKAGE_STRING);
2877 stun_agent_set_software (&agent->stun_agent, agent->software_attribute);
2879 agent_unlock ();