Make if/else serie a bit clearer
[sipe-libnice.git] / agent / agent.c
blob43c83095b89bf9c771332c50fcc1c9f67b8a6814
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 * (length must be between 22 and 256 chars)
1046 * @pwd: NULL-terminated string containing an ICE password
1047 * (length must be between 4 and 256 chars)
1049 * @return TRUE on success
1051 NICEAPI_EXPORT gboolean
1052 nice_agent_set_remote_credentials (
1053 NiceAgent *agent,
1054 guint stream_id,
1055 const gchar *ufrag, const gchar *pwd)
1057 Stream *stream;
1058 gboolean ret = FALSE;
1060 g_static_rec_mutex_lock (&agent->mutex);
1062 stream = agent_find_stream (agent, stream_id);
1063 /* note: oddly enough, ufrag and pwd can be empty strings */
1064 if (stream && ufrag && pwd) {
1066 g_strlcpy (stream->remote_ufrag, ufrag, NICE_STREAM_MAX_UFRAG);
1067 g_strlcpy (stream->remote_password, pwd, NICE_STREAM_MAX_PWD);
1069 ret = TRUE;
1070 goto done;
1073 done:
1074 g_static_rec_mutex_unlock (&agent->mutex);
1075 return ret;
1079 * Gets the local credentials for stream 'stream_id'.
1081 * @agent: a NiceAgent
1082 * @stream_id: identifier returnedby nice_agent_add_stream()
1083 * @ufrag: a pointer to a NULL-terminated string containing
1084 * an ICE username fragment [OUT]
1085 * @pwd: a pointer to a NULL-terminated string containing an ICE
1086 * password [OUT]
1088 * @return TRUE on success
1090 NICEAPI_EXPORT gboolean
1091 nice_agent_get_local_credentials (
1092 NiceAgent *agent,
1093 guint stream_id,
1094 const gchar **ufrag, const gchar **pwd)
1096 Stream *stream;
1097 gboolean ret = TRUE;
1099 g_static_rec_mutex_lock (&agent->mutex);
1101 stream = agent_find_stream (agent, stream_id);
1102 if (stream == NULL) {
1103 goto done;
1106 if (!ufrag || !pwd) {
1107 goto done;
1110 *ufrag = stream->local_ufrag;
1111 *pwd = stream->local_password;
1112 ret = TRUE;
1114 done:
1116 g_static_rec_mutex_unlock (&agent->mutex);
1117 return ret;
1121 * nice_agent_add_remote_candidate
1122 * @agent: a NiceAgent
1123 * @stream_id: the ID of the stream the candidate is for
1124 * @component_id: the ID of the component the candidate is for
1125 * @type: the type of the new candidate
1126 * @addr: the new candidate's IP address
1127 * @username: the new candidate's username (XXX: candidates don't have usernames)
1128 * @password: the new candidate's password (XXX: candidates don't have usernames)
1130 * Add a candidate our peer has informed us about to the agent's list.
1132 * Note: NICE_AGENT_MAX_REMOTE_CANDIDATES is the absolute
1133 * maximum limit for remote candidates
1134 * @return FALSE on fatal (memory alloc) errors
1136 NICEAPI_EXPORT gboolean
1137 nice_agent_add_remote_candidate (
1138 NiceAgent *agent,
1139 guint stream_id,
1140 guint component_id,
1141 NiceCandidateType type,
1142 NiceAddress *addr,
1143 const gchar *username,
1144 const gchar *password)
1147 /* XXX: to be deprecated */
1149 g_static_rec_mutex_lock (&agent->mutex);
1151 /* XXX: should we allow use of this method without an
1152 * initial call to nice_agent_set_remote_candidates()
1153 * with an empty set? */
1155 gboolean ret =
1156 priv_add_remote_candidate (agent,
1157 stream_id,
1158 component_id,
1159 type,
1160 addr,
1161 NULL,
1162 NICE_CANDIDATE_TRANSPORT_UDP,
1164 username,
1165 password,
1166 NULL);
1168 /* XXX/later: for each component, generate a new check with the new
1169 candidate, see below set_remote_candidates() */
1172 g_static_rec_mutex_unlock (&agent->mutex);
1173 return ret;
1177 * nice_agent_set_remote_candidates
1178 * @agent: a NiceAgent
1179 * @stream_id: the ID of the stream the candidate is for
1180 * @component_id: the ID of the component the candidate is for
1181 * @candidates: a list of NiceCandidate items describing the candidates
1183 * Sets the remote candidates for a component of a stream. Replaces
1184 * any existing remote candidates.
1186 * Note: NICE_AGENT_MAX_REMOTE_CANDIDATES is the absolute
1187 * maximum limit for remote candidates
1189 * @return number of candidates added, negative on fatal (memory
1190 * allocs) errors
1192 NICEAPI_EXPORT int
1193 nice_agent_set_remote_candidates (NiceAgent *agent, guint stream_id, guint component_id, const GSList *candidates)
1195 const GSList *i;
1196 int added = 0;
1199 if (agent->discovery_unsched_items > 0)
1200 return -1;
1202 g_static_rec_mutex_lock (&agent->mutex);
1204 for (i = candidates; i && added >= 0; i = i->next) {
1205 NiceCandidate *d = (NiceCandidate*) i->data;
1206 gboolean res =
1207 priv_add_remote_candidate (agent,
1208 stream_id,
1209 component_id,
1210 d->type,
1211 &d->addr,
1212 &d->base_addr,
1213 d->transport,
1214 d->priority,
1215 d->username,
1216 d->password,
1217 d->foundation);
1218 if (res)
1219 ++added;
1220 else
1221 added = -1;
1224 conn_check_remote_candidates_set(agent);
1226 if (added > 0) {
1227 gboolean res = conn_check_schedule_next (agent);
1228 if (res != TRUE)
1229 g_debug ("Agent %p : Warning: unable to schedule any conn checks!", agent);
1232 g_static_rec_mutex_unlock (&agent->mutex);
1233 return added;
1238 * Reads data from a ready, nonblocking socket attached to an ICE
1239 * stream component.
1241 * @return number of octets received, or negative on error
1243 static gint
1244 _nice_agent_recv (
1245 NiceAgent *agent,
1246 Stream *stream,
1247 Component *component,
1248 NiceUDPSocket *udp_socket,
1249 guint buf_len,
1250 gchar *buf)
1252 NiceAddress from;
1253 gint len;
1255 len = nice_udp_socket_recv (udp_socket, &from,
1256 buf_len, buf);
1258 #ifndef NDEBUG
1259 if (len >= 0) {
1260 gchar tmpbuf[INET6_ADDRSTRLEN];
1261 nice_address_to_string (&from, tmpbuf);
1262 g_debug ("Agent %p : Packet received on local socket %u from [%s]:%u (%u octets).", agent,
1263 udp_socket->fileno, tmpbuf, nice_address_get_port (&from), len);
1265 #endif
1267 if (len == 0)
1268 return 0;
1270 if ((guint)len > buf_len)
1272 /* buffer is not big enough to accept this packet */
1273 /* XXX: test this case */
1274 return 0;
1277 if (nice_address_equal (&from, &component->turn_server)) {
1278 GSList * i = NULL;
1279 g_debug ("Agent %p : Packet received from TURN server candidate.", agent);
1280 for (i = component->local_candidates; i; i = i->next) {
1281 NiceCandidate *cand = i->data;
1282 if (cand->type == NICE_CANDIDATE_TYPE_RELAYED) {
1283 len = nice_udp_turn_socket_parse_recv (cand->sockptr, &from, len, buf, &from, buf, len);
1288 if (!stun_message_validate_buffer_length ((uint8_t *) buf, (size_t) len) ==
1289 len)
1290 /* If the retval is no 0, its not a valid stun packet, probably data */
1291 return len;
1294 if (conn_check_handle_inbound_stun (agent, stream, component, udp_socket,
1295 &from, buf, len))
1296 /* handled STUN message*/
1297 return 0;
1299 /* unhandled STUN, pass to client */
1300 return len;
1304 * nice_agent_recv:
1305 * @agent: a NiceAgent
1306 * @stream_id: the ID of the stream to recieve data from
1307 * @component_id: the ID of the component to receive data from
1308 * @buf_len: the size of @buf
1309 * @buf: the buffer to read data into
1311 * Receive data on a particular component.
1313 * Returns: the amount of data read into @buf
1315 NICEAPI_EXPORT guint
1316 nice_agent_recv (
1317 NiceAgent *agent,
1318 guint stream_id,
1319 guint component_id,
1320 guint buf_len,
1321 gchar *buf)
1323 gint len = 0;
1324 fd_set fds;
1325 guint max_fd = 0;
1326 gint num_readable;
1327 GSList *i;
1328 Stream *stream;
1329 Component *component;
1330 guint ret = 0;
1332 g_static_rec_mutex_lock (&agent->mutex);
1333 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1334 goto done;
1337 FD_ZERO (&fds);
1339 for (i = component->sockets; i; i = i->next)
1341 NiceUDPSocket *sockptr = i->data;
1343 FD_SET (sockptr->fileno, &fds);
1344 max_fd = MAX (sockptr->fileno, max_fd);
1347 /* Loop on candidate sockets until we find one that has non-STUN data
1348 * waiting on it.
1351 for (;;)
1353 num_readable = select (max_fd + 1, &fds, NULL, NULL, NULL);
1354 g_assert (num_readable >= 0);
1356 if (num_readable > 0)
1358 guint j;
1360 for (j = 0; j <= max_fd; j++)
1361 if (FD_ISSET (j, &fds))
1363 NiceUDPSocket *socket;
1365 socket = component_find_udp_socket_by_fd (component, j);
1366 g_assert (socket);
1368 len = _nice_agent_recv (agent, stream, component, socket,
1369 buf_len, buf);
1371 if (len >= 0) {
1372 ret = len;
1373 goto done;
1379 /* note: commented out to avoid compiler warnings
1381 * g_assert_not_reached (); */
1382 done:
1383 g_static_rec_mutex_unlock (&agent->mutex);
1384 return ret;
1387 NICEAPI_EXPORT guint
1388 nice_agent_recv_sock (
1389 NiceAgent *agent,
1390 guint stream_id,
1391 guint component_id,
1392 guint sock,
1393 guint buf_len,
1394 gchar *buf)
1396 NiceUDPSocket *socket;
1397 Stream *stream;
1398 Component *component;
1399 guint ret = 0;
1401 g_static_rec_mutex_lock (&agent->mutex);
1402 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1403 goto done;
1406 socket = component_find_udp_socket_by_fd (component, sock);
1407 g_assert (socket);
1409 ret = _nice_agent_recv (agent, stream, component,
1410 socket, buf_len, buf);
1412 done:
1413 g_static_rec_mutex_unlock (&agent->mutex);
1414 return ret;
1419 * nice_agent_poll_read:
1420 * @agent: A NiceAgent
1421 * @other_fds: A GSList of other file descriptors to poll
1423 * Polls the agent's sockets until at least one of them is readable, and
1424 * additionally if @other_fds is not NULL, polls those for readability too.
1425 * @other_fds should contain the file descriptors directly, i.e. using
1426 * GUINT_TO_POINTER.
1428 * Returns: A list of file descriptors from @other_fds that are readable
1430 NICEAPI_EXPORT GSList *
1431 nice_agent_poll_read (
1432 NiceAgent *agent,
1433 GSList *other_fds,
1434 NiceAgentRecvFunc func,
1435 gpointer data)
1437 fd_set fds;
1438 guint max_fd = 0;
1439 gint num_readable;
1440 GSList *ret = NULL;
1441 GSList *i;
1442 guint j;
1444 g_static_rec_mutex_lock (&agent->mutex);
1446 FD_ZERO (&fds);
1448 for (i = agent->streams; i; i = i->next)
1450 GSList *j, *k;
1451 Stream *stream = i->data;
1453 for (k = stream->components; k; k = k->next)
1455 Component *component = k->data;
1457 for (j = component->sockets; j; j = j->next)
1459 NiceUDPSocket *sockptr = j->data;
1461 FD_SET (sockptr->fileno, &fds);
1462 max_fd = MAX (sockptr->fileno, max_fd);
1467 for (i = other_fds; i; i = i->next)
1469 guint fileno;
1471 fileno = GPOINTER_TO_UINT (i->data);
1472 FD_SET (fileno, &fds);
1473 max_fd = MAX (fileno, max_fd);
1476 num_readable = select (max_fd + 1, &fds, NULL, NULL, NULL);
1478 if (num_readable < 1) {
1479 /* none readable, or error */
1480 goto done;
1483 for (j = 0; j <= max_fd; j++)
1484 if (FD_ISSET (j, &fds))
1486 if (g_slist_find (other_fds, GUINT_TO_POINTER (j))) {
1487 GSList *modified_list = g_slist_append (ret, GUINT_TO_POINTER (j));
1488 if (modified_list == NULL) {
1489 g_slist_free (ret);
1490 goto done;
1492 ret = modified_list;
1494 else
1496 NiceUDPSocket *socket = NULL;
1497 Stream *stream = NULL;
1498 Component *component = NULL;
1499 gchar buf[MAX_BUFFER_SIZE];
1500 guint len;
1502 for (i = agent->streams; i; i = i->next)
1504 Stream *s = i->data;
1505 Component *c = stream_find_component_by_fd (s, j);
1507 socket = component_find_udp_socket_by_fd (c, j);
1509 if (socket != NULL) {
1510 stream = s;
1511 component = c;
1512 break;
1516 if (socket == NULL || stream == NULL || component == NULL)
1517 break;
1519 len = _nice_agent_recv (agent, stream, component,
1520 socket, MAX_BUFFER_SIZE, buf);
1522 if (len && func != NULL)
1523 func (agent, stream->id, component->id, len, buf,
1524 data);
1528 done:
1529 g_static_rec_mutex_unlock (&agent->mutex);
1530 return ret;
1536 * Sends a data payload over a stream component.
1538 * @pre component state MUST be NICE_COMPONENT_STATE_READY,
1539 * or as a special case, in any state if component was
1540 * in READY state before and was then restarted
1542 * @return number of bytes sent, or negative error code
1544 NICEAPI_EXPORT gint
1545 nice_agent_send (
1546 NiceAgent *agent,
1547 guint stream_id,
1548 guint component_id,
1549 guint len,
1550 const gchar *buf)
1552 Stream *stream;
1553 Component *component;
1554 guint ret = -1;
1556 g_static_rec_mutex_lock (&agent->mutex);
1558 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1559 goto done;
1562 if (component->selected_pair.local != NULL)
1564 NiceUDPSocket *sock;
1565 NiceAddress *addr;
1567 #ifndef NDEBUG
1568 gchar tmpbuf[INET6_ADDRSTRLEN];
1569 nice_address_to_string (&component->selected_pair.remote->addr, tmpbuf);
1571 g_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", agent, stream_id, component_id,
1572 len, tmpbuf,
1573 nice_address_get_port (&component->selected_pair.remote->addr));
1574 #endif
1576 sock = component->selected_pair.local->sockptr;
1577 addr = &component->selected_pair.remote->addr;
1578 nice_udp_socket_send (sock, addr, len, buf);
1579 component->media_after_tick = TRUE;
1581 ret = len;
1582 goto done;
1585 done:
1586 g_static_rec_mutex_unlock (&agent->mutex);
1587 return ret;
1592 * nice_agent_get_local_candidates:
1593 * @agent: A NiceAgent
1595 * The caller owns the returned GSList but not the candidates contained within
1596 * it. To get full results, the client should wait for the
1597 * 'candidates-gathering-done' signal.
1599 * Returns: a GSList of local candidates (NiceCandidate) belonging to @agent
1601 NICEAPI_EXPORT GSList *
1602 nice_agent_get_local_candidates (
1603 NiceAgent *agent,
1604 guint stream_id,
1605 guint component_id)
1607 Component *component;
1608 GSList * ret = NULL;
1609 GSList * item = NULL;
1611 g_static_rec_mutex_lock (&agent->mutex);
1612 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
1614 goto done;
1617 for (item = component->local_candidates; item; item = item->next)
1618 ret = g_slist_append (ret, nice_candidate_copy (item->data));
1620 done:
1621 g_static_rec_mutex_unlock (&agent->mutex);
1622 return ret;
1627 * nice_agent_get_remote_candidates:
1628 * @agent: A NiceAgent
1630 * The caller owns the returned GSList but not the candidates contained within
1631 * it.
1633 * Note: the list of remote candidates can change during processing.
1634 * The client should register for the "new-remote-candidate" signal to
1635 * get notification of new remote candidates.
1637 * Returns: a GSList of remote candidates (NiceCandidate) belonging to @agent
1639 NICEAPI_EXPORT GSList *
1640 nice_agent_get_remote_candidates (
1641 NiceAgent *agent,
1642 guint stream_id,
1643 guint component_id)
1645 Component *component;
1646 GSList *ret = NULL, *item = NULL;
1648 g_static_rec_mutex_lock (&agent->mutex);
1649 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
1651 goto done;
1654 for (item = component->remote_candidates; item; item = item->next)
1655 ret = g_slist_append (ret, nice_candidate_copy (item->data));
1657 done:
1658 g_static_rec_mutex_unlock (&agent->mutex);
1659 return ret;
1663 * nice_agent_restart
1664 * @agent: A NiceAgent
1666 * Restarts the session as defined in ICE spec (ID-19). This function
1667 * needs to be called both when initiating (ICE spec section 9.1.1.1.
1668 * "ICE Restarts"), as well as when reacting (spec section 9.2.1.1.
1669 * "Detecting ICE Restart") to a restart.
1671 * Returns: FALSE on error
1673 gboolean
1674 nice_agent_restart (
1675 NiceAgent *agent)
1677 GSList *i;
1678 gboolean res = TRUE;
1680 g_static_rec_mutex_lock (&agent->mutex);
1682 /* step: clean up all connectivity checks */
1683 conn_check_free (agent);
1685 /* step: regenerate tie-breaker value */
1686 priv_generate_tie_breaker (agent);
1688 for (i = agent->streams; i && res; i = i->next) {
1689 Stream *stream = i->data;
1691 /* step: reset local credentials for the stream and
1692 * clean up the list of remote candidates */
1693 res = stream_restart (stream, agent->rng);
1696 g_static_rec_mutex_unlock (&agent->mutex);
1697 return res;
1700 static void
1701 nice_agent_dispose (GObject *object)
1703 GSList *i;
1704 NiceAgent *agent = NICE_AGENT (object);
1706 /* step: free resources for the binding discovery timers */
1707 discovery_free (agent);
1708 g_assert (agent->discovery_list == NULL);
1710 /* step: free resources for the connectivity check timers */
1711 conn_check_free (agent);
1713 priv_remove_keepalive_timer (agent);
1715 for (i = agent->local_addresses; i; i = i->next)
1717 NiceAddress *a = i->data;
1719 nice_address_free (a);
1722 g_slist_free (agent->local_addresses);
1723 agent->local_addresses = NULL;
1725 for (i = agent->streams; i; i = i->next)
1727 Stream *s = i->data;
1729 stream_free (s);
1732 g_slist_free (agent->streams);
1733 agent->streams = NULL;
1735 g_free (agent->stun_server_ip);
1736 agent->stun_server_ip = NULL;
1738 nice_rng_free (agent->rng);
1739 agent->rng = NULL;
1741 if (G_OBJECT_CLASS (nice_agent_parent_class)->dispose)
1742 G_OBJECT_CLASS (nice_agent_parent_class)->dispose (object);
1744 nice_udp_socket_factory_close (&agent->udp_socket_factory);
1746 nice_udp_socket_factory_close (&agent->relay_socket_factory);
1749 g_static_rec_mutex_free (&agent->mutex);
1753 typedef struct _IOCtx IOCtx;
1755 struct _IOCtx
1757 NiceAgent *agent;
1758 Stream *stream;
1759 Component *component;
1760 NiceUDPSocket *socket;
1764 static IOCtx *
1765 io_ctx_new (
1766 NiceAgent *agent,
1767 Stream *stream,
1768 Component *component,
1769 NiceUDPSocket *socket)
1771 IOCtx *ctx;
1773 ctx = g_slice_new0 (IOCtx);
1774 if (ctx) {
1775 ctx->agent = agent;
1776 ctx->stream = stream;
1777 ctx->component = component;
1778 ctx->socket = socket;
1780 return ctx;
1784 static void
1785 io_ctx_free (IOCtx *ctx)
1787 g_slice_free (IOCtx, ctx);
1790 static gboolean
1791 nice_agent_g_source_cb (
1792 GIOChannel *source,
1793 G_GNUC_UNUSED
1794 GIOCondition condition,
1795 gpointer data)
1797 /* return value is whether to keep the source */
1799 IOCtx *ctx = data;
1800 NiceAgent *agent = ctx->agent;
1801 Stream *stream = ctx->stream;
1802 Component *component = ctx->component;
1803 gchar buf[MAX_BUFFER_SIZE];
1804 guint len;
1806 g_static_rec_mutex_lock (&agent->mutex);
1808 /* note: dear compiler, these are for you: */
1809 (void)source;
1811 len = _nice_agent_recv (agent, stream, component, ctx->socket,
1812 MAX_BUFFER_SIZE, buf);
1814 if (len > 0 && component->g_source_io_cb)
1815 component->g_source_io_cb (agent, stream->id, component->id,
1816 len, buf, component->data);
1818 g_static_rec_mutex_unlock (&agent->mutex);
1819 return TRUE;
1823 * Attaches one socket handle to the main loop event context
1826 void
1827 priv_attach_stream_component_socket (NiceAgent *agent,
1828 Stream *stream,
1829 Component *component,
1830 NiceUDPSocket *udp_socket)
1832 GIOChannel *io;
1833 GSource *source;
1834 IOCtx *ctx;
1836 if (!component->ctx)
1837 return;
1839 io = g_io_channel_unix_new (udp_socket->fileno);
1840 /* note: without G_IO_ERR the glib mainloop goes into
1841 * busyloop if errors are encountered */
1842 source = g_io_create_watch (io, G_IO_IN | G_IO_ERR);
1843 ctx = io_ctx_new (agent, stream, component, udp_socket);
1844 g_source_set_callback (source, (GSourceFunc) nice_agent_g_source_cb,
1845 ctx, (GDestroyNotify) io_ctx_free);
1846 g_debug ("Agent %p : Attach source %p (stream %u).", agent, source, stream->id);
1847 g_source_attach (source, component->ctx);
1848 component->gsources = g_slist_append (component->gsources, source);
1853 * Attaches socket handles of 'stream' to the main eventloop
1854 * context.
1857 static gboolean
1858 priv_attach_stream_component (NiceAgent *agent,
1859 Stream *stream,
1860 Component *component)
1862 GSList *i;
1864 for (i = component->sockets; i; i = i->next)
1865 priv_attach_stream_component_socket (agent, stream, component, i->data);
1867 return TRUE;
1871 * Detaches socket handles of 'stream' from the main eventloop
1872 * context.
1875 static void priv_detach_stream_component (Stream *stream, Component *component)
1877 GSList *i;
1879 for (i = component->gsources; i; i = i->next) {
1880 GSource *source = i->data;
1881 g_debug ("Detach source %p (stream %u).", source, stream->id);
1882 g_source_destroy (source);
1885 g_slist_free (component->gsources);
1886 component->gsources = NULL;
1889 NICEAPI_EXPORT gboolean
1890 nice_agent_attach_recv (
1891 NiceAgent *agent,
1892 guint stream_id,
1893 guint component_id,
1894 GMainContext *ctx,
1895 NiceAgentRecvFunc func,
1896 gpointer data)
1898 Component *component = NULL;
1899 Stream *stream = NULL;
1900 gboolean ret = FALSE;
1902 g_static_rec_mutex_lock (&agent->mutex);
1904 /* attach candidates */
1906 /* step: check that params specify an existing pair */
1907 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1908 g_warning ("Could not find component %u in stream %u", component_id,
1909 stream_id);
1910 goto done;
1913 if (component->g_source_io_cb && func == NULL)
1914 priv_detach_stream_component (stream, component);
1916 ret = TRUE;
1918 if (func && ctx) {
1919 component->g_source_io_cb = func;
1920 component->data = data;
1921 component->ctx = ctx;
1922 priv_attach_stream_component (agent, stream, component);
1923 } else {
1924 component->g_source_io_cb = NULL;
1925 component->data = NULL;
1926 component->ctx = NULL;
1930 done:
1931 g_static_rec_mutex_unlock (&agent->mutex);
1932 return ret;
1936 * Sets the selected candidate pair for media transmission
1937 * for given stream component. Calling this function will
1938 * disable all further ICE processing (connection check,
1939 * state machine updates, etc). Note that keepalives will
1940 * continue to be sent.
1942 NICEAPI_EXPORT gboolean
1943 nice_agent_set_selected_pair (
1944 NiceAgent *agent,
1945 guint stream_id,
1946 guint component_id,
1947 const gchar *lfoundation,
1948 const gchar *rfoundation)
1950 Component *component;
1951 Stream *stream;
1952 CandidatePair pair;
1953 gboolean ret = FALSE;
1955 g_static_rec_mutex_lock (&agent->mutex);
1957 /* step: check that params specify an existing pair */
1958 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1959 goto done;
1962 if (!component_find_pair (component, agent, lfoundation, rfoundation, &pair)){
1963 goto done;
1966 /* step: stop connectivity checks (note: for the whole stream) */
1967 conn_check_prune_stream (agent, stream);
1969 /* step: change component state */
1970 agent_signal_component_state_change (agent, stream_id, component_id, NICE_COMPONENT_STATE_READY);
1972 /* step: set the selected pair */
1973 component_update_selected_pair (component, &pair);
1974 agent_signal_new_selected_pair (agent, stream_id, component_id, lfoundation, rfoundation);
1976 ret = TRUE;
1978 done:
1979 g_static_rec_mutex_unlock (&agent->mutex);
1980 return ret;
1984 guint agent_timeout_add_with_context (NiceAgent *agent, guint interval,
1985 GSourceFunc function, gpointer data)
1987 GSource *source;
1988 guint id;
1990 g_return_val_if_fail (function != NULL, 0);
1992 source = g_timeout_source_new (interval);
1994 g_source_set_callback (source, function, data, NULL);
1995 id = g_source_attach (source, agent->main_context);
1996 g_source_unref (source);
1998 return id;
2003 * nice_agent_set_selected_remote_candidate:
2004 * @agent: a #NiceAgent
2005 * @stream_id: the stream id
2006 * @component_id: the component id
2007 * @candidate: the #NiceCandidate to force
2009 * Sets the selected remote candidate for media transmission
2010 * for given stream component. Calling this function will
2011 * disable all further ICE processing (connection check,
2012 * state machine updates, etc). Note that keepalives will
2013 * continue to be sent.
2015 * Returns: %TRUE on success, %FALSE on failure
2017 NICEAPI_EXPORT gboolean
2018 nice_agent_set_selected_remote_candidate (
2019 NiceAgent *agent,
2020 guint stream_id,
2021 guint component_id,
2022 NiceCandidate *candidate)
2024 Component *component;
2025 Stream *stream;
2026 NiceCandidate *lcandidate = NULL;
2027 gboolean ret = FALSE;
2029 g_static_rec_mutex_lock (&agent->mutex);
2031 /* step: check if the component exists*/
2032 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
2033 goto done;
2036 /* step: stop connectivity checks (note: for the whole stream) */
2037 conn_check_prune_stream (agent, stream);
2040 /* step: set the selected pair */
2041 lcandidate = component_set_selected_remote_candidate (agent, component,
2042 candidate);
2043 if (!lcandidate)
2044 goto done;
2046 /* step: change component state */
2047 agent_signal_component_state_change (agent, stream_id, component_id, NICE_COMPONENT_STATE_READY);
2049 agent_signal_new_selected_pair (agent, stream_id, component_id,
2050 lcandidate->foundation,
2051 candidate->foundation);
2053 ret = TRUE;
2055 done:
2056 g_static_rec_mutex_unlock (&agent->mutex);
2057 return ret;