Add warning on adding stream before local addresses
[sipe-libnice.git] / agent / agent.c
blob9443a7aab7f225d6dee20a85a49c728acbcd2726
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2006, 2007 Collabora Ltd.
5 * Contact: Dafydd Harries
6 * (C) 2006, 2007 Nokia Corporation. All rights reserved.
7 * Contact: Kai Vehmanen
9 * The contents of this file are subject to the Mozilla Public License Version
10 * 1.1 (the "License"); you may not use this file except in compliance with
11 * the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS" basis,
15 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 * for the specific language governing rights and limitations under the
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 * Kai Vehmanen, Nokia
28 * Alternatively, the contents of this file may be used under the terms of the
29 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
30 * case the provisions of LGPL are applicable instead of those above. If you
31 * wish to allow use of your version of this file only under the terms of the
32 * LGPL and not to allow others to use your version of this file under the
33 * MPL, indicate your decision by deleting the provisions above and replace
34 * them with the notice and other provisions required by the LGPL. If you do
35 * not delete the provisions above, a recipient may use your version of this
36 * file under either the MPL or the LGPL.
39 /**
40 * @file agent.c
41 * @brief ICE agent API implementation
44 #ifdef HAVE_CONFIG_H
45 # include <config.h>
46 #endif
48 #include <string.h>
49 #include <errno.h>
51 #include <sys/select.h>
52 #include <sys/socket.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
56 #include <glib.h>
58 #include "udp.h"
59 #include "udp-bsd.h"
60 #include "udp-turn.h"
61 #include "candidate.h"
62 #include "component.h"
63 #include "conncheck.h"
64 #include "discovery.h"
65 #include "agent.h"
66 #include "agent-priv.h"
67 #include "agent-signals-marshal.h"
69 #include "stream.h"
71 /* This is the max size of a UDP packet
72 * will it work tcp relaying??
74 #define MAX_BUFFER_SIZE 65536
75 #define DEFAULT_STUN_PORT 3478
78 G_DEFINE_TYPE (NiceAgent, nice_agent, G_TYPE_OBJECT);
80 enum
82 PROP_COMPATIBILITY = 1,
83 PROP_MAIN_CONTEXT,
84 PROP_STUN_SERVER,
85 PROP_STUN_SERVER_PORT,
86 PROP_CONTROLLING_MODE,
87 PROP_FULL_MODE,
88 PROP_STUN_PACING_TIMER,
89 PROP_MAX_CONNECTIVITY_CHECKS
93 enum
95 SIGNAL_COMPONENT_STATE_CHANGED,
96 SIGNAL_CANDIDATE_GATHERING_DONE,
97 SIGNAL_NEW_SELECTED_PAIR,
98 SIGNAL_NEW_CANDIDATE,
99 SIGNAL_NEW_REMOTE_CANDIDATE,
100 SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED,
101 N_SIGNALS,
105 static guint signals[N_SIGNALS];
107 static gboolean priv_attach_stream_component (NiceAgent *agent,
108 Stream *stream,
109 Component *component);
110 static void priv_detach_stream_component (Stream *stream, Component *component);
112 Stream *agent_find_stream (NiceAgent *agent, guint stream_id)
114 GSList *i;
116 for (i = agent->streams; i; i = i->next)
118 Stream *s = i->data;
120 if (s->id == stream_id)
121 return s;
124 return NULL;
128 gboolean
129 agent_find_component (
130 NiceAgent *agent,
131 guint stream_id,
132 guint component_id,
133 Stream **stream,
134 Component **component)
136 Stream *s;
137 Component *c;
139 s = agent_find_stream (agent, stream_id);
141 if (s == NULL)
142 return FALSE;
144 c = stream_find_component_by_id (s, component_id);
146 if (c == NULL)
147 return FALSE;
149 if (stream)
150 *stream = s;
152 if (component)
153 *component = c;
155 return TRUE;
159 static void
160 nice_agent_dispose (GObject *object);
162 static void
163 nice_agent_get_property (
164 GObject *object,
165 guint property_id,
166 GValue *value,
167 GParamSpec *pspec);
169 static void
170 nice_agent_set_property (
171 GObject *object,
172 guint property_id,
173 const GValue *value,
174 GParamSpec *pspec);
177 static void
178 nice_agent_class_init (NiceAgentClass *klass)
180 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
182 gobject_class->get_property = nice_agent_get_property;
183 gobject_class->set_property = nice_agent_set_property;
184 gobject_class->dispose = nice_agent_dispose;
186 /* install properties */
188 g_object_class_install_property (gobject_class, PROP_MAIN_CONTEXT,
189 g_param_spec_pointer (
190 "main-context",
191 "The GMainContext to use for timeouts",
192 "The GMainContext to use for timeouts",
193 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
195 g_object_class_install_property (gobject_class, PROP_COMPATIBILITY,
196 g_param_spec_uint (
197 "compatibility",
198 "ICE specification compatibility",
199 "The compatibility mode for the agent",
200 NICE_COMPATIBILITY_ID19, NICE_COMPATIBILITY_LAST,
201 NICE_COMPATIBILITY_ID19,
202 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
204 g_object_class_install_property (gobject_class, PROP_STUN_SERVER,
205 g_param_spec_string (
206 "stun-server",
207 "STUN server",
208 "The STUN server used to obtain server-reflexive candidates",
209 NULL,
210 G_PARAM_READWRITE));
212 g_object_class_install_property (gobject_class, PROP_STUN_SERVER_PORT,
213 g_param_spec_uint (
214 "stun-server-port",
215 "STUN server port",
216 "The STUN server used to obtain server-reflexive candidates",
217 1, 65536,
218 1, /* not a construct property, ignored */
219 G_PARAM_READWRITE));
221 g_object_class_install_property (gobject_class, PROP_CONTROLLING_MODE,
222 g_param_spec_boolean (
223 "controlling-mode",
224 "ICE controlling mode",
225 "Whether the agent is in controlling mode",
226 FALSE, /* not a construct property, ignored */
227 G_PARAM_READWRITE));
229 g_object_class_install_property (gobject_class, PROP_FULL_MODE,
230 g_param_spec_boolean (
231 "full-mode",
232 "ICE full mode",
233 "Whether agent runs in ICE full mode",
234 TRUE, /* use full mode by default */
235 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
237 g_object_class_install_property (gobject_class, PROP_STUN_PACING_TIMER,
238 g_param_spec_uint (
239 "stun-pacing-timer",
240 "STUN pacing timer",
241 "Timer 'Ta' (msecs) used in the IETF ICE specification for pacing candidate gathering and sending of connectivity checks",
242 1, 0xffffffff,
243 NICE_AGENT_TIMER_TA_DEFAULT,
244 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
246 /* note: according to spec recommendation in sect 5.7.3 (ID-19) */
247 g_object_class_install_property (gobject_class, PROP_MAX_CONNECTIVITY_CHECKS,
248 g_param_spec_uint (
249 "max-connectivity-checks",
250 "Maximum number of connectivity checks",
251 "Upper limit for the total number of connectivity checks performed",
252 0, 0xffffffff,
253 0, /* default set in init */
254 G_PARAM_READWRITE));
256 /* install signals */
258 /* signature: void cb(NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer self) */
259 signals[SIGNAL_COMPONENT_STATE_CHANGED] =
260 g_signal_new (
261 "component-state-changed",
262 G_OBJECT_CLASS_TYPE (klass),
263 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
265 NULL,
266 NULL,
267 agent_marshal_VOID__UINT_UINT_UINT,
268 G_TYPE_NONE,
270 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
271 G_TYPE_INVALID);
273 /* signature: void cb(NiceAgent *agent, gpointer self) */
274 signals[SIGNAL_CANDIDATE_GATHERING_DONE] =
275 g_signal_new (
276 "candidate-gathering-done",
277 G_OBJECT_CLASS_TYPE (klass),
278 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
280 NULL,
281 NULL,
282 agent_marshal_VOID__VOID,
283 G_TYPE_NONE,
285 G_TYPE_INVALID);
287 /* signature: void cb(NiceAgent *agent, guint stream_id, guint component_id,
288 gchar *lfoundation, gchar* rfoundation, gpointer self) */
289 signals[SIGNAL_NEW_SELECTED_PAIR] =
290 g_signal_new (
291 "new-selected-pair",
292 G_OBJECT_CLASS_TYPE (klass),
293 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
295 NULL,
296 NULL,
297 agent_marshal_VOID__UINT_UINT_STRING_STRING,
298 G_TYPE_NONE,
300 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING,
301 G_TYPE_INVALID);
303 /* signature: void cb(NiceAgent *agent, guint stream_id, guint component_id, gchar *foundation) */
304 signals[SIGNAL_NEW_CANDIDATE] =
305 g_signal_new (
306 "new-candidate",
307 G_OBJECT_CLASS_TYPE (klass),
308 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
310 NULL,
311 NULL,
312 agent_marshal_VOID__UINT_UINT_STRING,
313 G_TYPE_NONE,
315 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
316 G_TYPE_INVALID);
318 /* signature: void cb(NiceAgent *agent, guint stream_id, guint component_id, gchar *foundation) */
319 signals[SIGNAL_NEW_REMOTE_CANDIDATE] =
320 g_signal_new (
321 "new-remote-candidate",
322 G_OBJECT_CLASS_TYPE (klass),
323 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
325 NULL,
326 NULL,
327 agent_marshal_VOID__UINT_UINT_STRING,
328 G_TYPE_NONE,
330 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
331 G_TYPE_INVALID);
333 /* signature: void cb(NiceAgent *agent, guint stream_id, gpointer self) */
334 signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED] =
335 g_signal_new (
336 "initial-binding-request-received",
337 G_OBJECT_CLASS_TYPE (klass),
338 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
340 NULL,
341 NULL,
342 agent_marshal_VOID__UINT,
343 G_TYPE_NONE,
345 G_TYPE_UINT,
346 G_TYPE_INVALID);
350 static void priv_generate_tie_breaker (NiceAgent *agent)
352 nice_rng_generate_bytes (agent->rng, 8, (gchar*)&agent->tie_breaker);
355 static void
356 nice_agent_init (NiceAgent *agent)
358 agent->next_candidate_id = 1;
359 agent->next_stream_id = 1;
361 /* set defaults; not construct params, so set here */
362 agent->stun_server_port = DEFAULT_STUN_PORT;
363 agent->controlling_mode = TRUE;
364 agent->max_conn_checks = NICE_AGENT_MAX_CONNECTIVITY_CHECKS_DEFAULT;
366 agent->discovery_list = NULL;
367 agent->discovery_unsched_items = 0;
368 agent->discovery_timer_id = 0;
369 agent->conncheck_timer_id = 0;
370 agent->keepalive_timer_id = 0;
371 agent->compatibility = NICE_COMPATIBILITY_ID19;
373 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
374 STUN_COMPATIBILITY_3489BIS,
375 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
376 STUN_AGENT_USAGE_USE_FINGERPRINT);
378 nice_udp_bsd_socket_factory_init (&agent->udp_socket_factory);
379 nice_udp_turn_socket_factory_init (&agent->relay_socket_factory);
381 agent->rng = nice_rng_new ();
382 priv_generate_tie_breaker (agent);
384 g_static_rec_mutex_init (&agent->mutex);
389 * nice_agent_new:
391 * Create a new NiceAgent.
393 * Returns: the new agent
395 NICEAPI_EXPORT NiceAgent *
396 nice_agent_new (GMainContext *ctx, NiceCompatibility compat)
398 NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
399 "compatibility", compat,
400 "main-context", ctx,
401 NULL);
403 return agent;
407 static void
408 nice_agent_get_property (
409 GObject *object,
410 guint property_id,
411 GValue *value,
412 GParamSpec *pspec)
414 NiceAgent *agent = NICE_AGENT (object);
416 g_static_rec_mutex_lock (&agent->mutex);
418 switch (property_id)
420 case PROP_MAIN_CONTEXT:
421 g_value_set_pointer (value, agent->main_context);
422 break;
424 case PROP_COMPATIBILITY:
425 g_value_set_uint (value, agent->compatibility);
426 break;
428 case PROP_STUN_SERVER:
429 g_value_set_string (value, agent->stun_server_ip);
430 break;
432 case PROP_STUN_SERVER_PORT:
433 g_value_set_uint (value, agent->stun_server_port);
434 break;
436 case PROP_CONTROLLING_MODE:
437 g_value_set_boolean (value, agent->controlling_mode);
438 break;
440 case PROP_FULL_MODE:
441 g_value_set_boolean (value, agent->full_mode);
442 break;
444 case PROP_STUN_PACING_TIMER:
445 g_value_set_uint (value, agent->timer_ta);
446 break;
448 case PROP_MAX_CONNECTIVITY_CHECKS:
449 g_value_set_uint (value, agent->max_conn_checks);
450 /* XXX: should we prune the list of already existing checks? */
451 break;
453 default:
454 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
457 g_static_rec_mutex_unlock (&agent->mutex);
461 static void
462 nice_agent_set_property (
463 GObject *object,
464 guint property_id,
465 const GValue *value,
466 GParamSpec *pspec)
468 NiceAgent *agent = NICE_AGENT (object);
470 g_static_rec_mutex_lock (&agent->mutex);
472 switch (property_id)
474 case PROP_MAIN_CONTEXT:
475 agent->main_context = g_value_get_pointer (value);
476 break;
478 case PROP_COMPATIBILITY:
479 agent->compatibility = g_value_get_uint (value);
480 if (agent->compatibility == NICE_COMPATIBILITY_ID19) {
481 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
482 STUN_COMPATIBILITY_3489BIS,
483 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
484 STUN_AGENT_USAGE_USE_FINGERPRINT);
485 } else if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
486 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
487 STUN_COMPATIBILITY_RFC3489,
488 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
489 STUN_AGENT_USAGE_IGNORE_CREDENTIALS);
490 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN) {
491 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
492 STUN_COMPATIBILITY_RFC3489,
493 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
494 STUN_AGENT_USAGE_FORCE_VALIDATER);
497 break;
499 case PROP_STUN_SERVER:
500 agent->stun_server_ip = g_value_dup_string (value);
501 break;
503 case PROP_STUN_SERVER_PORT:
504 agent->stun_server_port = g_value_get_uint (value);
505 break;
507 case PROP_CONTROLLING_MODE:
508 agent->controlling_mode = g_value_get_boolean (value);
509 break;
511 case PROP_FULL_MODE:
512 agent->full_mode = g_value_get_boolean (value);
513 break;
515 case PROP_STUN_PACING_TIMER:
516 agent->timer_ta = g_value_get_uint (value);
517 break;
519 case PROP_MAX_CONNECTIVITY_CHECKS:
520 agent->max_conn_checks = g_value_get_uint (value);
521 break;
523 default:
524 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
527 g_static_rec_mutex_unlock (&agent->mutex);
531 void agent_gathering_done (NiceAgent *agent)
534 GSList *i, *j, *k, *l, *m;
536 for (i = agent->streams; i; i = i->next) {
537 Stream *stream = i->data;
538 for (j = stream->components; j; j = j->next) {
539 Component *component = j->data;
541 for (k = component->local_candidates; k; k = k->next) {
542 NiceCandidate *local_candidate = k->data;
544 for (l = component->remote_candidates; l; l = l->next) {
545 NiceCandidate *remote_candidate = l->data;
547 for (m = stream->conncheck_list; m; m = m->next) {
548 CandidateCheckPair *p = m->data;
550 if (p->local == local_candidate && p->remote == remote_candidate)
551 break;
553 if (m == NULL) {
554 conn_check_add_for_candidate (agent, stream->id, component, remote_candidate);
561 agent_signal_gathering_done (agent);
564 void agent_signal_gathering_done (NiceAgent *agent)
566 g_signal_emit (agent, signals[SIGNAL_CANDIDATE_GATHERING_DONE], 0);
569 void agent_signal_initial_binding_request_received (NiceAgent *agent, Stream *stream)
571 if (stream->initial_binding_request_received != TRUE) {
572 stream->initial_binding_request_received = TRUE;
573 g_signal_emit (agent, signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED], 0, stream->id);
577 void agent_signal_new_selected_pair (NiceAgent *agent, guint stream_id, guint component_id, const gchar *local_foundation, const gchar *remote_foundation)
579 Component *component;
580 gchar *lf_copy;
581 gchar *rf_copy;
583 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
584 return;
586 lf_copy = g_strdup (local_foundation);
587 rf_copy = g_strdup (remote_foundation);
590 g_signal_emit (agent, signals[SIGNAL_NEW_SELECTED_PAIR], 0,
591 stream_id, component_id, lf_copy, rf_copy);
593 g_free (lf_copy);
594 g_free (rf_copy);
597 void agent_signal_new_candidate (NiceAgent *agent, NiceCandidate *candidate)
599 g_signal_emit (agent, signals[SIGNAL_NEW_CANDIDATE], 0,
600 candidate->stream_id,
601 candidate->component_id,
602 candidate->foundation);
605 void agent_signal_new_remote_candidate (NiceAgent *agent, NiceCandidate *candidate)
607 g_signal_emit (agent, signals[SIGNAL_NEW_REMOTE_CANDIDATE], 0,
608 candidate->stream_id,
609 candidate->component_id,
610 candidate->foundation);
613 void agent_signal_component_state_change (NiceAgent *agent, guint stream_id, guint component_id, NiceComponentState state)
615 Component *component;
617 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
618 return;
620 if (component->state != state && state < NICE_COMPONENT_STATE_LAST) {
621 g_debug ("Agent %p : stream %u component %u STATE-CHANGE %u -> %u.", agent,
622 stream_id, component_id, component->state, state);
624 component->state = state;
626 g_signal_emit (agent, signals[SIGNAL_COMPONENT_STATE_CHANGED], 0,
627 stream_id, component_id, state);
631 guint64
632 agent_candidate_pair_priority (NiceAgent *agent, NiceCandidate *local, NiceCandidate *remote)
634 if (agent->controlling_mode)
635 return nice_candidate_pair_priority (local->priority, remote->priority);
636 else
637 return nice_candidate_pair_priority (remote->priority, local->priority);
640 static gboolean
641 priv_add_new_candidate_discovery (NiceAgent *agent,
642 NiceCandidate *host_candidate, NiceAddress server,
643 Stream *stream, guint component_id,
644 NiceAddress *addr, NiceCandidateType type)
646 CandidateDiscovery *cdisco;
647 GSList *modified_list;
649 /* note: no need to check for redundant candidates, as this is
650 * done later on in the process */
652 cdisco = g_slice_new0 (CandidateDiscovery);
653 if (cdisco) {
654 modified_list = g_slist_append (agent->discovery_list, cdisco);
656 if (modified_list) {
657 cdisco->type = type;
658 cdisco->socket = host_candidate->sockptr->fileno;
659 cdisco->nicesock = host_candidate->sockptr;
660 cdisco->server = server;
661 cdisco->interface = addr;
662 cdisco->stream = stream;
663 cdisco->component = stream_find_component_by_id (stream, component_id);
664 cdisco->agent = agent;
665 g_debug ("Agent %p : Adding new srv-rflx candidate discovery %p\n", agent, cdisco);
666 agent->discovery_list = modified_list;
667 ++agent->discovery_unsched_items;
670 return TRUE;
673 return FALSE;
678 * nice_agent_add_stream:
679 * @agent: a NiceAgent
680 * @n_components: number of components
682 * Add a data stream to @agent.
684 * @pre local addresses must be set with nice_agent_add_local_address()
686 * Returns: the ID of the new stream, 0 on failure
688 NICEAPI_EXPORT guint
689 nice_agent_add_stream (
690 NiceAgent *agent,
691 guint n_components)
693 Stream *stream;
694 GSList *modified_list = NULL;
695 guint ret = 0;
697 g_static_rec_mutex_lock (&agent->mutex);
699 if (!agent->local_addresses) {
700 g_warn_if_fail(agent->local_addresses);
701 goto done;
704 stream = stream_new (n_components);
705 if (stream) {
706 modified_list = g_slist_append (agent->streams, stream);
707 if (modified_list) {
708 stream->id = agent->next_stream_id++;
709 g_debug ("Agent %p : allocating stream id %u (%p)", agent, stream->id, stream);
711 stream_initialize_credentials (stream, agent->rng);
713 agent->streams = modified_list;
715 else
716 stream_free (stream);
719 ret = stream->id;
721 done:
722 g_static_rec_mutex_unlock (&agent->mutex);
723 return ret;
727 NICEAPI_EXPORT void nice_agent_set_relay_info(NiceAgent *agent,
728 guint stream_id, guint component_id,
729 const gchar *server_ip, guint server_port,
730 const gchar *username, const gchar *password)
733 Component *component = NULL;
735 g_static_rec_mutex_lock (&agent->mutex);
737 if (agent_find_component (agent, stream_id, component_id, NULL, &component)) {
738 nice_address_init (&component->turn_server);
740 if (nice_address_set_from_string (&component->turn_server, server_ip)) {
741 nice_address_set_port (&component->turn_server, server_port);
744 g_free (component->turn_username);
745 component->turn_username = g_strdup (username);
747 g_free (component->turn_password);
748 component->turn_password = g_strdup (password);
750 g_static_rec_mutex_unlock (&agent->mutex);
755 * nice_agent_gather_candidates:
757 * start the candidate gathering process
760 NICEAPI_EXPORT void
761 nice_agent_gather_candidates (
762 NiceAgent *agent,
763 guint stream_id)
765 guint n;
766 GSList *i;
767 Stream *stream;
769 g_static_rec_mutex_lock (&agent->mutex);
771 stream = agent_find_stream (agent, stream_id);
772 if (stream == NULL) {
773 goto done;
776 g_debug ("Agent %p : In %s mode, starting candidate gathering.", agent, agent->full_mode ? "ICE-FULL" : "ICE-LITE");
778 /* generate a local host candidate for each local address */
780 for (i = agent->local_addresses; i; i = i->next)
782 NiceAddress *addr = i->data;
783 NiceCandidate *host_candidate;
785 for (n = 0; n < stream->n_components; n++) {
786 Component *component = stream_find_component_by_id (stream, n + 1);
787 host_candidate = discovery_add_local_host_candidate (agent, stream->id,
788 n + 1, addr);
790 if (!host_candidate) {
791 g_error ("No host candidate??");
792 break;
795 if (agent->full_mode &&
796 agent->stun_server_ip) {
797 NiceAddress stun_server;
798 if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
799 nice_address_set_port (&stun_server, agent->stun_server_port);
801 gboolean res =
802 priv_add_new_candidate_discovery (agent,
803 host_candidate,
804 stun_server,
805 stream,
806 n + 1 /* component-id */,
807 addr,
808 NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE);
810 if (res != TRUE) {
811 /* note: memory allocation failure, return error */
812 g_error ("Memory allocation failure?");
816 if (agent->full_mode &&
817 component && nice_address_is_valid (&component->turn_server)) {
819 gboolean res =
820 priv_add_new_candidate_discovery (agent,
821 host_candidate,
822 component->turn_server,
823 stream,
824 n + 1 /* component-id */,
825 addr,
826 NICE_CANDIDATE_TYPE_RELAYED);
828 if (res != TRUE) {
829 /* note: memory allocation failure, return error */
830 g_error ("Memory allocation failure?");
837 /* note: no async discoveries pending, signal that we are ready */
838 if (agent->discovery_unsched_items == 0) {
839 agent_gathering_done (agent);
840 } else {
841 g_assert (agent->discovery_list);
842 discovery_schedule (agent);
845 done:
847 g_static_rec_mutex_unlock (&agent->mutex);
850 static void priv_remove_keepalive_timer (NiceAgent *agent)
852 if (agent->keepalive_timer_id) {
853 g_source_remove (agent->keepalive_timer_id),
854 agent->keepalive_timer_id = 0;
859 * nice_agent_remove_stream:
860 * @agent: a NiceAgent
861 * @stream_id: the ID of the stream to remove
863 NICEAPI_EXPORT void
864 nice_agent_remove_stream (
865 NiceAgent *agent,
866 guint stream_id)
868 /* note that streams/candidates can be in use by other threads */
870 Stream *stream;
871 GSList *i;
873 g_static_rec_mutex_lock (&agent->mutex);
874 stream = agent_find_stream (agent, stream_id);
876 if (!stream) {
877 goto done;
880 /* note: remove items with matching stream_ids from both lists */
881 conn_check_prune_stream (agent, stream);
882 discovery_prune_stream (agent, stream_id);
884 /* remove the stream itself */
885 for (i = stream->components; i; i = i->next) {
886 priv_detach_stream_component (stream, (Component *) i->data);
889 agent->streams = g_slist_remove (agent->streams, stream);
890 stream_free (stream);
892 if (!agent->streams)
893 priv_remove_keepalive_timer (agent);
895 done:
896 g_static_rec_mutex_unlock (&agent->mutex);
900 * nice_agent_add_local_address:
901 * @agent: A NiceAgent
902 * @addr: the address of a local IP interface
904 * Inform the agent of the presence of an address that a local
905 * network interface is bound to.
907 * @return FALSE on fatal (memory allocation) errors
909 NICEAPI_EXPORT gboolean
910 nice_agent_add_local_address (NiceAgent *agent, NiceAddress *addr)
912 NiceAddress *dup;
913 GSList *modified_list;
914 gboolean ret = FALSE;
916 g_static_rec_mutex_lock (&agent->mutex);
918 dup = nice_address_dup (addr);
919 nice_address_set_port (dup, 0);
920 modified_list = g_slist_append (agent->local_addresses, dup);
921 if (modified_list) {
922 agent->local_addresses = modified_list;
924 ret = TRUE;
925 goto done;
928 done:
929 g_static_rec_mutex_unlock (&agent->mutex);
930 return ret;
934 * Adds a new, or updates an existing, remote candidate.
936 * @return TRUE if candidate was succesfully added or
937 * update, otherwise FALSE
939 static gboolean priv_add_remote_candidate (
940 NiceAgent *agent,
941 guint stream_id,
942 guint component_id,
943 NiceCandidateType type,
944 const NiceAddress *addr,
945 const NiceAddress *base_addr,
946 NiceCandidateTransport transport,
947 guint32 priority,
948 const gchar *username,
949 const gchar *password,
950 const gchar *foundation)
952 Component *component;
953 NiceCandidate *candidate;
954 gchar *username_dup = NULL, *password_dup = NULL;
955 gboolean error_flag = FALSE;
957 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
958 return FALSE;
960 /* step: check whether the candidate already exists */
961 candidate = component_find_remote_candidate(component, addr, transport);
962 if (candidate) {
963 g_debug ("Agent %p : Update existing remote candidate %p.", agent, candidate);
964 /* case 1: an existing candidate, update the attributes */
965 candidate->type = type;
966 if (base_addr)
967 candidate->base_addr = *base_addr;
968 candidate->priority = priority;
969 if (foundation)
970 strncpy(candidate->foundation, foundation, NICE_CANDIDATE_MAX_FOUNDATION);
971 /* note: username and password must remain the same during
972 * a session; see sect 9.1.2 in ICE ID-19 */
973 if (conn_check_add_for_candidate (agent, stream_id, component, candidate) < 0)
974 error_flag = TRUE;
976 else {
977 /* case 2: add a new candidate */
978 if (username)
979 username_dup = g_strdup (username);
980 if (password)
981 password_dup = g_strdup (password);
983 candidate = nice_candidate_new (type);
984 if (candidate) {
985 GSList *modified_list = g_slist_append (component->remote_candidates, candidate);
986 if (modified_list) {
987 component->remote_candidates = modified_list;
989 candidate->stream_id = stream_id;
990 candidate->component_id = component_id;
992 candidate->type = type;
993 if (addr)
994 candidate->addr = *addr;
995 #ifndef NDEBUG
997 gchar tmpbuf[INET6_ADDRSTRLEN];
998 nice_address_to_string (addr, tmpbuf);
999 g_debug ("Agent %p : Adding remote candidate with addr [%s]:%u.", agent, tmpbuf,
1000 nice_address_get_port (addr));
1002 #endif
1004 if (base_addr)
1005 candidate->base_addr = *base_addr;
1007 candidate->transport = transport;
1008 candidate->priority = priority;
1009 candidate->username = username_dup;
1010 candidate->password = password_dup;
1012 if (foundation)
1013 g_strlcpy (candidate->foundation, foundation, NICE_CANDIDATE_MAX_FOUNDATION);
1015 if (conn_check_add_for_candidate (agent, stream_id, component, candidate) < 0)
1016 error_flag = TRUE;
1018 else /* memory alloc error: list insert */
1019 error_flag = TRUE;
1021 else /* memory alloc error: candidate creation */
1022 error_flag = TRUE;
1025 if (error_flag) {
1026 if (candidate)
1027 nice_candidate_free (candidate);
1028 g_free (username_dup);
1029 g_free (password_dup);
1030 return FALSE;
1033 return TRUE;
1037 * Sets the remote credentials for stream 'stream_id'.
1039 * Note: stream credentials do not override per-candidate
1040 * credentials if set
1042 * @agent: a NiceAgent
1043 * @stream_id: identifier returnedby nice_agent_add_stream()
1044 * @ufrag: NULL-terminated string containing an ICE username fragment
1045 * @pwd: NULL-terminated string containing an ICE password
1047 * @return TRUE on success
1049 NICEAPI_EXPORT gboolean
1050 nice_agent_set_remote_credentials (
1051 NiceAgent *agent,
1052 guint stream_id,
1053 const gchar *ufrag, const gchar *pwd)
1055 Stream *stream;
1056 gboolean ret = FALSE;
1058 g_static_rec_mutex_lock (&agent->mutex);
1060 stream = agent_find_stream (agent, stream_id);
1061 /* note: oddly enough, ufrag and pwd can be empty strings */
1062 if (stream && ufrag && pwd) {
1064 g_strlcpy (stream->remote_ufrag, ufrag, NICE_STREAM_MAX_UFRAG);
1065 g_strlcpy (stream->remote_password, pwd, NICE_STREAM_MAX_PWD);
1067 ret = TRUE;
1068 goto done;
1071 done:
1072 g_static_rec_mutex_unlock (&agent->mutex);
1073 return ret;
1077 * Gets the local credentials for stream 'stream_id'.
1079 * @agent: a NiceAgent
1080 * @stream_id: identifier returnedby nice_agent_add_stream()
1081 * @ufrag: a pointer to a NULL-terminated string containing
1082 * an ICE username fragment [OUT]
1083 * @pwd: a pointer to a NULL-terminated string containing an ICE
1084 * password [OUT]
1086 * @return TRUE on success
1088 NICEAPI_EXPORT gboolean
1089 nice_agent_get_local_credentials (
1090 NiceAgent *agent,
1091 guint stream_id,
1092 const gchar **ufrag, const gchar **pwd)
1094 Stream *stream;
1095 gboolean ret = TRUE;
1097 g_static_rec_mutex_lock (&agent->mutex);
1099 stream = agent_find_stream (agent, stream_id);
1100 if (stream == NULL) {
1101 goto done;
1104 if (!ufrag || !pwd) {
1105 goto done;
1108 *ufrag = stream->local_ufrag;
1109 *pwd = stream->local_password;
1110 ret = TRUE;
1112 done:
1114 g_static_rec_mutex_unlock (&agent->mutex);
1115 return ret;
1119 * nice_agent_add_remote_candidate
1120 * @agent: a NiceAgent
1121 * @stream_id: the ID of the stream the candidate is for
1122 * @component_id: the ID of the component the candidate is for
1123 * @type: the type of the new candidate
1124 * @addr: the new candidate's IP address
1125 * @username: the new candidate's username (XXX: candidates don't have usernames)
1126 * @password: the new candidate's password (XXX: candidates don't have usernames)
1128 * Add a candidate our peer has informed us about to the agent's list.
1130 * Note: NICE_AGENT_MAX_REMOTE_CANDIDATES is the absolute
1131 * maximum limit for remote candidates
1132 * @return FALSE on fatal (memory alloc) errors
1134 NICEAPI_EXPORT gboolean
1135 nice_agent_add_remote_candidate (
1136 NiceAgent *agent,
1137 guint stream_id,
1138 guint component_id,
1139 NiceCandidateType type,
1140 NiceAddress *addr,
1141 const gchar *username,
1142 const gchar *password)
1145 /* XXX: to be deprecated */
1147 g_static_rec_mutex_lock (&agent->mutex);
1149 /* XXX: should we allow use of this method without an
1150 * initial call to nice_agent_set_remote_candidates()
1151 * with an empty set? */
1153 gboolean ret =
1154 priv_add_remote_candidate (agent,
1155 stream_id,
1156 component_id,
1157 type,
1158 addr,
1159 NULL,
1160 NICE_CANDIDATE_TRANSPORT_UDP,
1162 username,
1163 password,
1164 NULL);
1166 /* XXX/later: for each component, generate a new check with the new
1167 candidate, see below set_remote_candidates() */
1170 g_static_rec_mutex_unlock (&agent->mutex);
1171 return ret;
1175 * nice_agent_set_remote_candidates
1176 * @agent: a NiceAgent
1177 * @stream_id: the ID of the stream the candidate is for
1178 * @component_id: the ID of the component the candidate is for
1179 * @candidates: a list of NiceCandidate items describing the candidates
1181 * Sets the remote candidates for a component of a stream. Replaces
1182 * any existing remote candidates.
1184 * Note: NICE_AGENT_MAX_REMOTE_CANDIDATES is the absolute
1185 * maximum limit for remote candidates
1187 * @return number of candidates added, negative on fatal (memory
1188 * allocs) errors
1190 NICEAPI_EXPORT int
1191 nice_agent_set_remote_candidates (NiceAgent *agent, guint stream_id, guint component_id, const GSList *candidates)
1193 const GSList *i;
1194 int added = 0;
1197 if (agent->discovery_unsched_items > 0)
1198 return -1;
1200 g_static_rec_mutex_lock (&agent->mutex);
1202 for (i = candidates; i && added >= 0; i = i->next) {
1203 NiceCandidate *d = (NiceCandidate*) i->data;
1204 gboolean res =
1205 priv_add_remote_candidate (agent,
1206 stream_id,
1207 component_id,
1208 d->type,
1209 &d->addr,
1210 &d->base_addr,
1211 d->transport,
1212 d->priority,
1213 d->username,
1214 d->password,
1215 d->foundation);
1216 if (res)
1217 ++added;
1218 else
1219 added = -1;
1222 conn_check_remote_candidates_set(agent);
1224 if (added > 0) {
1225 gboolean res = conn_check_schedule_next (agent);
1226 if (res != TRUE)
1227 g_debug ("Agent %p : Warning: unable to schedule any conn checks!", agent);
1230 g_static_rec_mutex_unlock (&agent->mutex);
1231 return added;
1236 * Reads data from a ready, nonblocking socket attached to an ICE
1237 * stream component.
1239 * @return number of octets received, or negative on error
1241 static gint
1242 _nice_agent_recv (
1243 NiceAgent *agent,
1244 Stream *stream,
1245 Component *component,
1246 NiceUDPSocket *udp_socket,
1247 guint buf_len,
1248 gchar *buf)
1250 NiceAddress from;
1251 gint len;
1253 len = nice_udp_socket_recv (udp_socket, &from,
1254 buf_len, buf);
1256 #ifndef NDEBUG
1257 if (len >= 0) {
1258 gchar tmpbuf[INET6_ADDRSTRLEN];
1259 nice_address_to_string (&from, tmpbuf);
1260 g_debug ("Agent %p : Packet received on local socket %u from [%s]:%u (%u octets).", agent,
1261 udp_socket->fileno, tmpbuf, nice_address_get_port (&from), len);
1263 #endif
1265 if (len == 0)
1266 return 0;
1268 if ((guint)len > buf_len)
1270 /* buffer is not big enough to accept this packet */
1271 /* XXX: test this case */
1272 return 0;
1275 if (nice_address_equal (&from, &component->turn_server)) {
1276 GSList * i = NULL;
1277 g_debug ("Agent %p : Packet received from TURN server candidate.", agent);
1278 for (i = component->local_candidates; i; i = i->next) {
1279 NiceCandidate *cand = i->data;
1280 if (cand->type == NICE_CANDIDATE_TYPE_RELAYED) {
1281 len = nice_udp_turn_socket_parse_recv (cand->sockptr, &from, len, buf, &from, buf, len);
1286 if (stun_message_validate_buffer_length ((uint8_t *) buf, (size_t) len) == len) {
1287 /* If the retval is no 0, its not a valid stun packet, probably data */
1288 if (conn_check_handle_inbound_stun (agent, stream, component, udp_socket,
1289 &from, buf, len) == FALSE) {
1290 /* unhandled STUN, pass to client */
1291 return len;
1293 } else {
1294 /* not STUN, pass to client */
1295 return len;
1298 /* handled STUN message*/
1299 return 0;
1303 * nice_agent_recv:
1304 * @agent: a NiceAgent
1305 * @stream_id: the ID of the stream to recieve data from
1306 * @component_id: the ID of the component to receive data from
1307 * @buf_len: the size of @buf
1308 * @buf: the buffer to read data into
1310 * Receive data on a particular component.
1312 * Returns: the amount of data read into @buf
1314 NICEAPI_EXPORT guint
1315 nice_agent_recv (
1316 NiceAgent *agent,
1317 guint stream_id,
1318 guint component_id,
1319 guint buf_len,
1320 gchar *buf)
1322 gint len = 0;
1323 fd_set fds;
1324 guint max_fd = 0;
1325 gint num_readable;
1326 GSList *i;
1327 Stream *stream;
1328 Component *component;
1329 guint ret = 0;
1331 g_static_rec_mutex_lock (&agent->mutex);
1332 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1333 goto done;
1336 FD_ZERO (&fds);
1338 for (i = component->sockets; i; i = i->next)
1340 NiceUDPSocket *sockptr = i->data;
1342 FD_SET (sockptr->fileno, &fds);
1343 max_fd = MAX (sockptr->fileno, max_fd);
1346 /* Loop on candidate sockets until we find one that has non-STUN data
1347 * waiting on it.
1350 for (;;)
1352 num_readable = select (max_fd + 1, &fds, NULL, NULL, NULL);
1353 g_assert (num_readable >= 0);
1355 if (num_readable > 0)
1357 guint j;
1359 for (j = 0; j <= max_fd; j++)
1360 if (FD_ISSET (j, &fds))
1362 NiceUDPSocket *socket;
1364 socket = component_find_udp_socket_by_fd (component, j);
1365 g_assert (socket);
1367 len = _nice_agent_recv (agent, stream, component, socket,
1368 buf_len, buf);
1370 if (len >= 0) {
1371 ret = len;
1372 goto done;
1378 /* note: commented out to avoid compiler warnings
1380 * g_assert_not_reached (); */
1381 done:
1382 g_static_rec_mutex_unlock (&agent->mutex);
1383 return ret;
1386 NICEAPI_EXPORT guint
1387 nice_agent_recv_sock (
1388 NiceAgent *agent,
1389 guint stream_id,
1390 guint component_id,
1391 guint sock,
1392 guint buf_len,
1393 gchar *buf)
1395 NiceUDPSocket *socket;
1396 Stream *stream;
1397 Component *component;
1398 guint ret = 0;
1400 g_static_rec_mutex_lock (&agent->mutex);
1401 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1402 goto done;
1405 socket = component_find_udp_socket_by_fd (component, sock);
1406 g_assert (socket);
1408 ret = _nice_agent_recv (agent, stream, component,
1409 socket, buf_len, buf);
1411 done:
1412 g_static_rec_mutex_unlock (&agent->mutex);
1413 return ret;
1418 * nice_agent_poll_read:
1419 * @agent: A NiceAgent
1420 * @other_fds: A GSList of other file descriptors to poll
1422 * Polls the agent's sockets until at least one of them is readable, and
1423 * additionally if @other_fds is not NULL, polls those for readability too.
1424 * @other_fds should contain the file descriptors directly, i.e. using
1425 * GUINT_TO_POINTER.
1427 * Returns: A list of file descriptors from @other_fds that are readable
1429 NICEAPI_EXPORT GSList *
1430 nice_agent_poll_read (
1431 NiceAgent *agent,
1432 GSList *other_fds,
1433 NiceAgentRecvFunc func,
1434 gpointer data)
1436 fd_set fds;
1437 guint max_fd = 0;
1438 gint num_readable;
1439 GSList *ret = NULL;
1440 GSList *i;
1441 guint j;
1443 g_static_rec_mutex_lock (&agent->mutex);
1445 FD_ZERO (&fds);
1447 for (i = agent->streams; i; i = i->next)
1449 GSList *j, *k;
1450 Stream *stream = i->data;
1452 for (k = stream->components; k; k = k->next)
1454 Component *component = k->data;
1456 for (j = component->sockets; j; j = j->next)
1458 NiceUDPSocket *sockptr = j->data;
1460 FD_SET (sockptr->fileno, &fds);
1461 max_fd = MAX (sockptr->fileno, max_fd);
1466 for (i = other_fds; i; i = i->next)
1468 guint fileno;
1470 fileno = GPOINTER_TO_UINT (i->data);
1471 FD_SET (fileno, &fds);
1472 max_fd = MAX (fileno, max_fd);
1475 num_readable = select (max_fd + 1, &fds, NULL, NULL, NULL);
1477 if (num_readable < 1) {
1478 /* none readable, or error */
1479 goto done;
1482 for (j = 0; j <= max_fd; j++)
1483 if (FD_ISSET (j, &fds))
1485 if (g_slist_find (other_fds, GUINT_TO_POINTER (j))) {
1486 GSList *modified_list = g_slist_append (ret, GUINT_TO_POINTER (j));
1487 if (modified_list == NULL) {
1488 g_slist_free (ret);
1489 goto done;
1491 ret = modified_list;
1493 else
1495 NiceUDPSocket *socket = NULL;
1496 Stream *stream = NULL;
1497 Component *component = NULL;
1498 gchar buf[MAX_BUFFER_SIZE];
1499 guint len;
1501 for (i = agent->streams; i; i = i->next)
1503 Stream *s = i->data;
1504 Component *c = stream_find_component_by_fd (s, j);
1506 socket = component_find_udp_socket_by_fd (c, j);
1508 if (socket != NULL) {
1509 stream = s;
1510 component = c;
1511 break;
1515 if (socket == NULL || stream == NULL || component == NULL)
1516 break;
1518 len = _nice_agent_recv (agent, stream, component,
1519 socket, MAX_BUFFER_SIZE, buf);
1521 if (len && func != NULL)
1522 func (agent, stream->id, component->id, len, buf,
1523 data);
1527 done:
1528 g_static_rec_mutex_unlock (&agent->mutex);
1529 return ret;
1535 * Sends a data payload over a stream component.
1537 * @pre component state MUST be NICE_COMPONENT_STATE_READY,
1538 * or as a special case, in any state if component was
1539 * in READY state before and was then restarted
1541 * @return number of bytes sent, or negative error code
1543 NICEAPI_EXPORT gint
1544 nice_agent_send (
1545 NiceAgent *agent,
1546 guint stream_id,
1547 guint component_id,
1548 guint len,
1549 const gchar *buf)
1551 Stream *stream;
1552 Component *component;
1553 guint ret = -1;
1555 g_static_rec_mutex_lock (&agent->mutex);
1557 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1558 goto done;
1561 if (component->selected_pair.local != NULL)
1563 NiceUDPSocket *sock;
1564 NiceAddress *addr;
1566 #ifndef NDEBUG
1567 gchar tmpbuf[INET6_ADDRSTRLEN];
1568 nice_address_to_string (&component->selected_pair.remote->addr, tmpbuf);
1570 g_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", agent, stream_id, component_id,
1571 len, tmpbuf,
1572 nice_address_get_port (&component->selected_pair.remote->addr));
1573 #endif
1575 sock = component->selected_pair.local->sockptr;
1576 addr = &component->selected_pair.remote->addr;
1577 nice_udp_socket_send (sock, addr, len, buf);
1578 component->media_after_tick = TRUE;
1580 ret = len;
1581 goto done;
1584 done:
1585 g_static_rec_mutex_unlock (&agent->mutex);
1586 return ret;
1591 * nice_agent_get_local_candidates:
1592 * @agent: A NiceAgent
1594 * The caller owns the returned GSList but not the candidates contained within
1595 * it. To get full results, the client should wait for the
1596 * 'candidates-gathering-done' signal.
1598 * Returns: a GSList of local candidates (NiceCandidate) belonging to @agent
1600 NICEAPI_EXPORT GSList *
1601 nice_agent_get_local_candidates (
1602 NiceAgent *agent,
1603 guint stream_id,
1604 guint component_id)
1606 Component *component;
1607 GSList * ret = NULL;
1608 GSList * item = NULL;
1610 g_static_rec_mutex_lock (&agent->mutex);
1611 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
1613 goto done;
1616 for (item = component->local_candidates; item; item = item->next)
1617 ret = g_slist_append (ret, nice_candidate_copy (item->data));
1619 done:
1620 g_static_rec_mutex_unlock (&agent->mutex);
1621 return ret;
1626 * nice_agent_get_remote_candidates:
1627 * @agent: A NiceAgent
1629 * The caller owns the returned GSList but not the candidates contained within
1630 * it.
1632 * Note: the list of remote candidates can change during processing.
1633 * The client should register for the "new-remote-candidate" signal to
1634 * get notification of new remote candidates.
1636 * Returns: a GSList of remote candidates (NiceCandidate) belonging to @agent
1638 NICEAPI_EXPORT GSList *
1639 nice_agent_get_remote_candidates (
1640 NiceAgent *agent,
1641 guint stream_id,
1642 guint component_id)
1644 Component *component;
1645 GSList *ret = NULL, *item = NULL;
1647 g_static_rec_mutex_lock (&agent->mutex);
1648 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
1650 goto done;
1653 for (item = component->remote_candidates; item; item = item->next)
1654 ret = g_slist_append (ret, nice_candidate_copy (item->data));
1656 done:
1657 g_static_rec_mutex_unlock (&agent->mutex);
1658 return ret;
1662 * nice_agent_restart
1663 * @agent: A NiceAgent
1665 * Restarts the session as defined in ICE spec (ID-19). This function
1666 * needs to be called both when initiating (ICE spec section 9.1.1.1.
1667 * "ICE Restarts"), as well as when reacting (spec section 9.2.1.1.
1668 * "Detecting ICE Restart") to a restart.
1670 * Returns: FALSE on error
1672 gboolean
1673 nice_agent_restart (
1674 NiceAgent *agent)
1676 GSList *i;
1677 gboolean res = TRUE;
1679 g_static_rec_mutex_lock (&agent->mutex);
1681 /* step: clean up all connectivity checks */
1682 conn_check_free (agent);
1684 /* step: regenerate tie-breaker value */
1685 priv_generate_tie_breaker (agent);
1687 for (i = agent->streams; i && res; i = i->next) {
1688 Stream *stream = i->data;
1690 /* step: reset local credentials for the stream and
1691 * clean up the list of remote candidates */
1692 res = stream_restart (stream, agent->rng);
1695 g_static_rec_mutex_unlock (&agent->mutex);
1696 return res;
1699 static void
1700 nice_agent_dispose (GObject *object)
1702 GSList *i;
1703 NiceAgent *agent = NICE_AGENT (object);
1705 /* step: free resources for the binding discovery timers */
1706 discovery_free (agent);
1707 g_assert (agent->discovery_list == NULL);
1709 /* step: free resources for the connectivity check timers */
1710 conn_check_free (agent);
1712 priv_remove_keepalive_timer (agent);
1714 for (i = agent->local_addresses; i; i = i->next)
1716 NiceAddress *a = i->data;
1718 nice_address_free (a);
1721 g_slist_free (agent->local_addresses);
1722 agent->local_addresses = NULL;
1724 for (i = agent->streams; i; i = i->next)
1726 Stream *s = i->data;
1728 stream_free (s);
1731 g_slist_free (agent->streams);
1732 agent->streams = NULL;
1734 g_free (agent->stun_server_ip);
1735 agent->stun_server_ip = NULL;
1737 nice_rng_free (agent->rng);
1738 agent->rng = NULL;
1740 if (G_OBJECT_CLASS (nice_agent_parent_class)->dispose)
1741 G_OBJECT_CLASS (nice_agent_parent_class)->dispose (object);
1743 nice_udp_socket_factory_close (&agent->udp_socket_factory);
1745 nice_udp_socket_factory_close (&agent->relay_socket_factory);
1748 g_static_rec_mutex_free (&agent->mutex);
1752 typedef struct _IOCtx IOCtx;
1754 struct _IOCtx
1756 NiceAgent *agent;
1757 Stream *stream;
1758 Component *component;
1759 NiceUDPSocket *socket;
1763 static IOCtx *
1764 io_ctx_new (
1765 NiceAgent *agent,
1766 Stream *stream,
1767 Component *component,
1768 NiceUDPSocket *socket)
1770 IOCtx *ctx;
1772 ctx = g_slice_new0 (IOCtx);
1773 if (ctx) {
1774 ctx->agent = agent;
1775 ctx->stream = stream;
1776 ctx->component = component;
1777 ctx->socket = socket;
1779 return ctx;
1783 static void
1784 io_ctx_free (IOCtx *ctx)
1786 g_slice_free (IOCtx, ctx);
1789 static gboolean
1790 nice_agent_g_source_cb (
1791 GIOChannel *source,
1792 G_GNUC_UNUSED
1793 GIOCondition condition,
1794 gpointer data)
1796 /* return value is whether to keep the source */
1798 IOCtx *ctx = data;
1799 NiceAgent *agent = ctx->agent;
1800 Stream *stream = ctx->stream;
1801 Component *component = ctx->component;
1802 gchar buf[MAX_BUFFER_SIZE];
1803 guint len;
1805 g_static_rec_mutex_lock (&agent->mutex);
1807 /* note: dear compiler, these are for you: */
1808 (void)source;
1810 len = _nice_agent_recv (agent, stream, component, ctx->socket,
1811 MAX_BUFFER_SIZE, buf);
1813 if (len > 0 && component->g_source_io_cb)
1814 component->g_source_io_cb (agent, stream->id, component->id,
1815 len, buf, component->data);
1817 g_static_rec_mutex_unlock (&agent->mutex);
1818 return TRUE;
1822 * Attaches one socket handle to the main loop event context
1825 void
1826 priv_attach_stream_component_socket (NiceAgent *agent,
1827 Stream *stream,
1828 Component *component,
1829 NiceUDPSocket *udp_socket)
1831 GIOChannel *io;
1832 GSource *source;
1833 IOCtx *ctx;
1835 if (!component->ctx)
1836 return;
1838 io = g_io_channel_unix_new (udp_socket->fileno);
1839 /* note: without G_IO_ERR the glib mainloop goes into
1840 * busyloop if errors are encountered */
1841 source = g_io_create_watch (io, G_IO_IN | G_IO_ERR);
1842 ctx = io_ctx_new (agent, stream, component, udp_socket);
1843 g_source_set_callback (source, (GSourceFunc) nice_agent_g_source_cb,
1844 ctx, (GDestroyNotify) io_ctx_free);
1845 g_debug ("Agent %p : Attach source %p (stream %u).", agent, source, stream->id);
1846 g_source_attach (source, component->ctx);
1847 component->gsources = g_slist_append (component->gsources, source);
1852 * Attaches socket handles of 'stream' to the main eventloop
1853 * context.
1856 static gboolean
1857 priv_attach_stream_component (NiceAgent *agent,
1858 Stream *stream,
1859 Component *component)
1861 GSList *i;
1863 for (i = component->sockets; i; i = i->next)
1864 priv_attach_stream_component_socket (agent, stream, component, i->data);
1866 return TRUE;
1870 * Detaches socket handles of 'stream' from the main eventloop
1871 * context.
1874 static void priv_detach_stream_component (Stream *stream, Component *component)
1876 GSList *i;
1878 for (i = component->gsources; i; i = i->next) {
1879 GSource *source = i->data;
1880 g_debug ("Detach source %p (stream %u).", source, stream->id);
1881 g_source_destroy (source);
1884 g_slist_free (component->gsources);
1885 component->gsources = NULL;
1888 NICEAPI_EXPORT gboolean
1889 nice_agent_attach_recv (
1890 NiceAgent *agent,
1891 guint stream_id,
1892 guint component_id,
1893 GMainContext *ctx,
1894 NiceAgentRecvFunc func,
1895 gpointer data)
1897 Component *component = NULL;
1898 Stream *stream = NULL;
1899 gboolean ret = FALSE;
1901 g_static_rec_mutex_lock (&agent->mutex);
1903 /* attach candidates */
1905 /* step: check that params specify an existing pair */
1906 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1907 g_warning ("Could not find component %u in stream %u", component_id,
1908 stream_id);
1909 goto done;
1912 if (component->g_source_io_cb && func == NULL)
1913 priv_detach_stream_component (stream, component);
1915 ret = TRUE;
1917 if (func && ctx) {
1918 component->g_source_io_cb = func;
1919 component->data = data;
1920 component->ctx = ctx;
1921 priv_attach_stream_component (agent, stream, component);
1922 } else {
1923 component->g_source_io_cb = NULL;
1924 component->data = NULL;
1925 component->ctx = NULL;
1929 done:
1930 g_static_rec_mutex_unlock (&agent->mutex);
1931 return ret;
1935 * Sets the selected candidate pair for media transmission
1936 * for given stream component. Calling this function will
1937 * disable all further ICE processing (connection check,
1938 * state machine updates, etc). Note that keepalives will
1939 * continue to be sent.
1941 NICEAPI_EXPORT gboolean
1942 nice_agent_set_selected_pair (
1943 NiceAgent *agent,
1944 guint stream_id,
1945 guint component_id,
1946 const gchar *lfoundation,
1947 const gchar *rfoundation)
1949 Component *component;
1950 Stream *stream;
1951 CandidatePair pair;
1952 gboolean ret = FALSE;
1954 g_static_rec_mutex_lock (&agent->mutex);
1956 /* step: check that params specify an existing pair */
1957 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1958 goto done;
1961 if (!component_find_pair (component, agent, lfoundation, rfoundation, &pair)){
1962 goto done;
1965 /* step: stop connectivity checks (note: for the whole stream) */
1966 conn_check_prune_stream (agent, stream);
1968 /* step: change component state */
1969 agent_signal_component_state_change (agent, stream_id, component_id, NICE_COMPONENT_STATE_READY);
1971 /* step: set the selected pair */
1972 component_update_selected_pair (component, &pair);
1973 agent_signal_new_selected_pair (agent, stream_id, component_id, lfoundation, rfoundation);
1975 ret = TRUE;
1977 done:
1978 g_static_rec_mutex_unlock (&agent->mutex);
1979 return ret;
1983 guint agent_timeout_add_with_context (NiceAgent *agent, guint interval,
1984 GSourceFunc function, gpointer data)
1986 GSource *source;
1987 guint id;
1989 g_return_val_if_fail (function != NULL, 0);
1991 source = g_timeout_source_new (interval);
1993 g_source_set_callback (source, function, data, NULL);
1994 id = g_source_attach (source, agent->main_context);
1995 g_source_unref (source);
1997 return id;
2002 * nice_agent_set_selected_remote_candidate:
2003 * @agent: a #NiceAgent
2004 * @stream_id: the stream id
2005 * @component_id: the component id
2006 * @candidate: the #NiceCandidate to force
2008 * Sets the selected remote candidate for media transmission
2009 * for given stream component. Calling this function will
2010 * disable all further ICE processing (connection check,
2011 * state machine updates, etc). Note that keepalives will
2012 * continue to be sent.
2014 * Returns: %TRUE on success, %FALSE on failure
2016 NICEAPI_EXPORT gboolean
2017 nice_agent_set_selected_remote_candidate (
2018 NiceAgent *agent,
2019 guint stream_id,
2020 guint component_id,
2021 NiceCandidate *candidate)
2023 Component *component;
2024 Stream *stream;
2025 NiceCandidate *lcandidate = NULL;
2026 gboolean ret = FALSE;
2028 g_static_rec_mutex_lock (&agent->mutex);
2030 /* step: check if the component exists*/
2031 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
2032 goto done;
2035 /* step: stop connectivity checks (note: for the whole stream) */
2036 conn_check_prune_stream (agent, stream);
2039 /* step: set the selected pair */
2040 lcandidate = component_set_selected_remote_candidate (agent, component,
2041 candidate);
2042 if (!lcandidate)
2043 goto done;
2045 /* step: change component state */
2046 agent_signal_component_state_change (agent, stream_id, component_id, NICE_COMPONENT_STATE_READY);
2048 agent_signal_new_selected_pair (agent, stream_id, component_id,
2049 lcandidate->foundation,
2050 candidate->foundation);
2052 ret = TRUE;
2054 done:
2055 g_static_rec_mutex_unlock (&agent->mutex);
2056 return ret;