Refuse invalid relay informations
[sipe-libnice.git] / agent / agent.c
blob5acf41848ccab2edf23429622af809d0389f0dd9
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.
40 #ifdef HAVE_CONFIG_H
41 # include <config.h>
42 #else
43 #define NICEAPI_EXPORT
44 #endif
46 #include <glib.h>
48 #include <string.h>
49 #include <errno.h>
51 #ifdef G_OS_WIN32
52 #include <winsock2.h>
53 #else
54 #include <sys/socket.h>
55 #include <netinet/in.h>
56 #include <arpa/inet.h>
57 #endif
59 #include "debug.h"
61 #include "socket.h"
62 #include "stun/usages/turn.h"
63 #include "candidate.h"
64 #include "component.h"
65 #include "conncheck.h"
66 #include "discovery.h"
67 #include "agent.h"
68 #include "agent-priv.h"
69 #include "agent-signals-marshal.h"
71 #include "stream.h"
72 #include "interfaces.h"
74 /* This is the max size of a UDP packet
75 * will it work tcp relaying??
77 #define MAX_BUFFER_SIZE 65536
78 #define DEFAULT_STUN_PORT 3478
81 G_DEFINE_TYPE (NiceAgent, nice_agent, G_TYPE_OBJECT);
83 enum
85 PROP_COMPATIBILITY = 1,
86 PROP_MAIN_CONTEXT,
87 PROP_STUN_SERVER,
88 PROP_STUN_SERVER_PORT,
89 PROP_CONTROLLING_MODE,
90 PROP_FULL_MODE,
91 PROP_STUN_PACING_TIMER,
92 PROP_MAX_CONNECTIVITY_CHECKS,
93 PROP_PROXY_TYPE,
94 PROP_PROXY_IP,
95 PROP_PROXY_PORT,
96 PROP_PROXY_USERNAME,
97 PROP_PROXY_PASSWORD
101 enum
103 SIGNAL_COMPONENT_STATE_CHANGED,
104 SIGNAL_CANDIDATE_GATHERING_DONE,
105 SIGNAL_NEW_SELECTED_PAIR,
106 SIGNAL_NEW_CANDIDATE,
107 SIGNAL_NEW_REMOTE_CANDIDATE,
108 SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED,
109 N_SIGNALS,
112 static guint signals[N_SIGNALS];
114 static gboolean priv_attach_stream_component (NiceAgent *agent,
115 Stream *stream,
116 Component *component);
117 static void priv_detach_stream_component (Stream *stream, Component *component);
119 StunUsageIceCompatibility
120 agent_to_ice_compatibility (NiceAgent *agent)
122 return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
123 STUN_USAGE_ICE_COMPATIBILITY_GOOGLE :
124 agent->compatibility == NICE_COMPATIBILITY_MSN ?
125 STUN_USAGE_ICE_COMPATIBILITY_MSN :
126 STUN_USAGE_ICE_COMPATIBILITY_DRAFT19;
130 StunUsageTurnCompatibility
131 agent_to_turn_compatibility (NiceAgent *agent)
133 return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
134 STUN_USAGE_TURN_COMPATIBILITY_GOOGLE :
135 agent->compatibility == NICE_COMPATIBILITY_MSN ?
136 STUN_USAGE_TURN_COMPATIBILITY_MSN :
137 agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
138 STUN_USAGE_TURN_COMPATIBILITY_MSN : STUN_USAGE_TURN_COMPATIBILITY_DRAFT9;
141 NiceTurnSocketCompatibility
142 agent_to_turn_socket_compatibility (NiceAgent *agent)
144 return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
145 NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE :
146 agent->compatibility == NICE_COMPATIBILITY_MSN ?
147 NICE_TURN_SOCKET_COMPATIBILITY_MSN :
148 agent->compatibility == NICE_COMPATIBILITY_WLM2009 ?
149 NICE_TURN_SOCKET_COMPATIBILITY_MSN :
150 NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9;
153 Stream *agent_find_stream (NiceAgent *agent, guint stream_id)
155 GSList *i;
157 for (i = agent->streams; i; i = i->next)
159 Stream *s = i->data;
161 if (s->id == stream_id)
162 return s;
165 return NULL;
169 gboolean
170 agent_find_component (
171 NiceAgent *agent,
172 guint stream_id,
173 guint component_id,
174 Stream **stream,
175 Component **component)
177 Stream *s;
178 Component *c;
180 s = agent_find_stream (agent, stream_id);
182 if (s == NULL)
183 return FALSE;
185 c = stream_find_component_by_id (s, component_id);
187 if (c == NULL)
188 return FALSE;
190 if (stream)
191 *stream = s;
193 if (component)
194 *component = c;
196 return TRUE;
200 static void
201 nice_agent_dispose (GObject *object);
203 static void
204 nice_agent_get_property (
205 GObject *object,
206 guint property_id,
207 GValue *value,
208 GParamSpec *pspec);
210 static void
211 nice_agent_set_property (
212 GObject *object,
213 guint property_id,
214 const GValue *value,
215 GParamSpec *pspec);
218 static void
219 nice_agent_class_init (NiceAgentClass *klass)
221 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
223 gobject_class->get_property = nice_agent_get_property;
224 gobject_class->set_property = nice_agent_set_property;
225 gobject_class->dispose = nice_agent_dispose;
227 /* install properties */
229 * NiceAgent:main-context:
231 * A GLib main context is needed for all timeouts used by libnice.
232 * This is a property being set by the nice_agent_new() call.
234 g_object_class_install_property (gobject_class, PROP_MAIN_CONTEXT,
235 g_param_spec_pointer (
236 "main-context",
237 "The GMainContext to use for timeouts",
238 "The GMainContext to use for timeouts",
239 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
242 * NiceAgent:compatibility:
244 * The Nice agent can work in various compatibility modes depending on
245 * what the application/peer needs.
246 * <para> See also: #NiceCompatibility</para>
248 g_object_class_install_property (gobject_class, PROP_COMPATIBILITY,
249 g_param_spec_uint (
250 "compatibility",
251 "ICE specification compatibility",
252 "The compatibility mode for the agent",
253 NICE_COMPATIBILITY_DRAFT19, NICE_COMPATIBILITY_LAST,
254 NICE_COMPATIBILITY_DRAFT19,
255 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
257 g_object_class_install_property (gobject_class, PROP_STUN_SERVER,
258 g_param_spec_string (
259 "stun-server",
260 "STUN server",
261 "The STUN server used to obtain server-reflexive candidates",
262 NULL,
263 G_PARAM_READWRITE));
265 g_object_class_install_property (gobject_class, PROP_STUN_SERVER_PORT,
266 g_param_spec_uint (
267 "stun-server-port",
268 "STUN server port",
269 "The STUN server used to obtain server-reflexive candidates",
270 1, 65536,
271 1, /* not a construct property, ignored */
272 G_PARAM_READWRITE));
274 g_object_class_install_property (gobject_class, PROP_CONTROLLING_MODE,
275 g_param_spec_boolean (
276 "controlling-mode",
277 "ICE controlling mode",
278 "Whether the agent is in controlling mode",
279 FALSE, /* not a construct property, ignored */
280 G_PARAM_READWRITE));
282 g_object_class_install_property (gobject_class, PROP_FULL_MODE,
283 g_param_spec_boolean (
284 "full-mode",
285 "ICE full mode",
286 "Whether agent runs in ICE full mode",
287 TRUE, /* use full mode by default */
288 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
290 g_object_class_install_property (gobject_class, PROP_STUN_PACING_TIMER,
291 g_param_spec_uint (
292 "stun-pacing-timer",
293 "STUN pacing timer",
294 "Timer 'Ta' (msecs) used in the IETF ICE specification for pacing candidate gathering and sending of connectivity checks",
295 1, 0xffffffff,
296 NICE_AGENT_TIMER_TA_DEFAULT,
297 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
299 /* note: according to spec recommendation in sect 5.7.3 (ID-19) */
300 g_object_class_install_property (gobject_class, PROP_MAX_CONNECTIVITY_CHECKS,
301 g_param_spec_uint (
302 "max-connectivity-checks",
303 "Maximum number of connectivity checks",
304 "Upper limit for the total number of connectivity checks performed",
305 0, 0xffffffff,
306 0, /* default set in init */
307 G_PARAM_READWRITE));
309 g_object_class_install_property (gobject_class, PROP_PROXY_IP,
310 g_param_spec_string (
311 "proxy-ip",
312 "Proxy server IP",
313 "The proxy server used to bypass a proxy firewall",
314 NULL,
315 G_PARAM_READWRITE));
317 g_object_class_install_property (gobject_class, PROP_PROXY_PORT,
318 g_param_spec_uint (
319 "proxy-port",
320 "Proxy server port",
321 "The Proxy server used to bypass a proxy firewall",
322 1, 65536,
324 G_PARAM_READWRITE));
326 g_object_class_install_property (gobject_class, PROP_PROXY_TYPE,
327 g_param_spec_uint (
328 "proxy-type",
329 "Type of proxy to use",
330 "The type of proxy set in the proxy-ip property",
331 NICE_PROXY_TYPE_NONE, NICE_PROXY_TYPE_LAST,
332 NICE_PROXY_TYPE_NONE,
333 G_PARAM_READWRITE));
335 g_object_class_install_property (gobject_class, PROP_PROXY_USERNAME,
336 g_param_spec_string (
337 "proxy-username",
338 "Proxy server username",
339 "The username used to authenticate with the proxy",
340 NULL,
341 G_PARAM_READWRITE));
343 g_object_class_install_property (gobject_class, PROP_PROXY_PASSWORD,
344 g_param_spec_string (
345 "proxy-password",
346 "Proxy server password",
347 "The password used to authenticate with the proxy",
348 NULL,
349 G_PARAM_READWRITE));
351 /* install signals */
354 * NiceAgent::component-state-changed
355 * @stream_id: The ID of the stream
356 * @component_id: The ID of the component
357 * @state: The #NiceComponentState of the component
359 * This signal is fired whenever a component's state changes
361 signals[SIGNAL_COMPONENT_STATE_CHANGED] =
362 g_signal_new (
363 "component-state-changed",
364 G_OBJECT_CLASS_TYPE (klass),
365 G_SIGNAL_RUN_LAST,
367 NULL,
368 NULL,
369 agent_marshal_VOID__UINT_UINT_UINT,
370 G_TYPE_NONE,
372 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
373 G_TYPE_INVALID);
376 * NiceAgent::candidate-gathering-done:
377 * @stream_id: The ID of the stream
379 * This signal is fired whenever a stream has finished gathering its
380 * candidates after a call to nice_agent_gather_candidates()
382 signals[SIGNAL_CANDIDATE_GATHERING_DONE] =
383 g_signal_new (
384 "candidate-gathering-done",
385 G_OBJECT_CLASS_TYPE (klass),
386 G_SIGNAL_RUN_LAST,
388 NULL,
389 NULL,
390 agent_marshal_VOID__UINT,
391 G_TYPE_NONE,
393 G_TYPE_UINT, G_TYPE_INVALID);
396 * NiceAgent::new-selected-pair
397 * @stream_id: The ID of the stream
398 * @component_id: The ID of the component
399 * @lfoundation: The local foundation of the selected candidate pair
400 * @rfoundation: The remote foundation of the selected candidate pair
402 * This signal is fired once a candidate pair is selected for data transfer for
403 * a stream's component
405 signals[SIGNAL_NEW_SELECTED_PAIR] =
406 g_signal_new (
407 "new-selected-pair",
408 G_OBJECT_CLASS_TYPE (klass),
409 G_SIGNAL_RUN_LAST,
411 NULL,
412 NULL,
413 agent_marshal_VOID__UINT_UINT_STRING_STRING,
414 G_TYPE_NONE,
416 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING,
417 G_TYPE_INVALID);
420 * NiceAgent::new-candidate
421 * @stream_id: The ID of the stream
422 * @component_id: The ID of the component
423 * @foundation: The foundation of the new candidate
425 * This signal is fired when the agent discovers a new candidate
426 * <para> See also: #NiceAgent::candidates-gathering-done </para>
428 signals[SIGNAL_NEW_CANDIDATE] =
429 g_signal_new (
430 "new-candidate",
431 G_OBJECT_CLASS_TYPE (klass),
432 G_SIGNAL_RUN_LAST,
434 NULL,
435 NULL,
436 agent_marshal_VOID__UINT_UINT_STRING,
437 G_TYPE_NONE,
439 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
440 G_TYPE_INVALID);
443 * NiceAgent::new-remote-candidate
444 * @stream_id: The ID of the stream
445 * @component_id: The ID of the component
446 * @foundation: The foundation of the new candidate
448 * This signal is fired when the agent discovers a new remote candidate.
449 * This can happen with peer reflexive candidates.
450 * <para> See also: #NiceAgent::candidates-gathering-done </para>
452 signals[SIGNAL_NEW_REMOTE_CANDIDATE] =
453 g_signal_new (
454 "new-remote-candidate",
455 G_OBJECT_CLASS_TYPE (klass),
456 G_SIGNAL_RUN_LAST,
458 NULL,
459 NULL,
460 agent_marshal_VOID__UINT_UINT_STRING,
461 G_TYPE_NONE,
463 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
464 G_TYPE_INVALID);
467 * NiceAgent::initial-binding-request-received
468 * @stream_id: The ID of the stream
470 * This signal is fired when we received our first binding request from
471 * the peer.
473 signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED] =
474 g_signal_new (
475 "initial-binding-request-received",
476 G_OBJECT_CLASS_TYPE (klass),
477 G_SIGNAL_RUN_LAST,
479 NULL,
480 NULL,
481 agent_marshal_VOID__UINT,
482 G_TYPE_NONE,
484 G_TYPE_UINT,
485 G_TYPE_INVALID);
487 /* Init debug options depending on env variables */
488 nice_debug_init ();
491 static void priv_generate_tie_breaker (NiceAgent *agent)
493 nice_rng_generate_bytes (agent->rng, 8, (gchar*)&agent->tie_breaker);
496 static void
497 nice_agent_init (NiceAgent *agent)
499 agent->next_candidate_id = 1;
500 agent->next_stream_id = 1;
502 /* set defaults; not construct params, so set here */
503 agent->stun_server_port = DEFAULT_STUN_PORT;
504 agent->controlling_mode = TRUE;
505 agent->max_conn_checks = NICE_AGENT_MAX_CONNECTIVITY_CHECKS_DEFAULT;
507 agent->discovery_list = NULL;
508 agent->discovery_unsched_items = 0;
509 agent->discovery_timer_source = NULL;
510 agent->conncheck_timer_source = NULL;
511 agent->keepalive_timer_source = NULL;
512 agent->refresh_list = NULL;
514 agent->compatibility = NICE_COMPATIBILITY_DRAFT19;
516 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
517 STUN_COMPATIBILITY_RFC5389,
518 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
519 STUN_AGENT_USAGE_USE_FINGERPRINT);
521 agent->rng = nice_rng_new ();
522 priv_generate_tie_breaker (agent);
524 g_static_rec_mutex_init (&agent->mutex);
528 NICEAPI_EXPORT NiceAgent *
529 nice_agent_new (GMainContext *ctx, NiceCompatibility compat)
531 NiceAgent *agent = g_object_new (NICE_TYPE_AGENT,
532 "compatibility", compat,
533 "main-context", ctx,
534 NULL);
536 return agent;
540 static void
541 nice_agent_get_property (
542 GObject *object,
543 guint property_id,
544 GValue *value,
545 GParamSpec *pspec)
547 NiceAgent *agent = NICE_AGENT (object);
549 g_static_rec_mutex_lock (&agent->mutex);
551 switch (property_id)
553 case PROP_MAIN_CONTEXT:
554 g_value_set_pointer (value, agent->main_context);
555 break;
557 case PROP_COMPATIBILITY:
558 g_value_set_uint (value, agent->compatibility);
559 break;
561 case PROP_STUN_SERVER:
562 g_value_set_string (value, agent->stun_server_ip);
563 break;
565 case PROP_STUN_SERVER_PORT:
566 g_value_set_uint (value, agent->stun_server_port);
567 break;
569 case PROP_CONTROLLING_MODE:
570 g_value_set_boolean (value, agent->controlling_mode);
571 break;
573 case PROP_FULL_MODE:
574 g_value_set_boolean (value, agent->full_mode);
575 break;
577 case PROP_STUN_PACING_TIMER:
578 g_value_set_uint (value, agent->timer_ta);
579 break;
581 case PROP_MAX_CONNECTIVITY_CHECKS:
582 g_value_set_uint (value, agent->max_conn_checks);
583 /* XXX: should we prune the list of already existing checks? */
584 break;
586 case PROP_PROXY_IP:
587 g_value_set_string (value, agent->proxy_ip);
588 break;
590 case PROP_PROXY_PORT:
591 g_value_set_uint (value, agent->proxy_port);
592 break;
594 case PROP_PROXY_TYPE:
595 g_value_set_uint (value, agent->proxy_type);
596 break;
598 case PROP_PROXY_USERNAME:
599 g_value_set_string (value, agent->proxy_username);
600 break;
602 case PROP_PROXY_PASSWORD:
603 g_value_set_string (value, agent->proxy_password);
604 break;
606 default:
607 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
610 g_static_rec_mutex_unlock (&agent->mutex);
614 static void
615 nice_agent_set_property (
616 GObject *object,
617 guint property_id,
618 const GValue *value,
619 GParamSpec *pspec)
621 NiceAgent *agent = NICE_AGENT (object);
623 g_static_rec_mutex_lock (&agent->mutex);
625 switch (property_id)
627 case PROP_MAIN_CONTEXT:
628 agent->main_context = g_value_get_pointer (value);
629 break;
631 case PROP_COMPATIBILITY:
632 agent->compatibility = g_value_get_uint (value);
633 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
634 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
635 STUN_COMPATIBILITY_RFC3489,
636 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
637 STUN_AGENT_USAGE_IGNORE_CREDENTIALS);
638 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN) {
639 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
640 STUN_COMPATIBILITY_RFC3489,
641 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
642 STUN_AGENT_USAGE_FORCE_VALIDATER);
643 } else if (agent->compatibility == NICE_COMPATIBILITY_WLM2009) {
644 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
645 STUN_COMPATIBILITY_WLM2009,
646 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
647 STUN_AGENT_USAGE_USE_FINGERPRINT);
648 } else {
649 stun_agent_init (&agent->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
650 STUN_COMPATIBILITY_RFC5389,
651 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
652 STUN_AGENT_USAGE_USE_FINGERPRINT);
655 break;
657 case PROP_STUN_SERVER:
658 agent->stun_server_ip = g_value_dup_string (value);
659 break;
661 case PROP_STUN_SERVER_PORT:
662 agent->stun_server_port = g_value_get_uint (value);
663 break;
665 case PROP_CONTROLLING_MODE:
666 agent->controlling_mode = g_value_get_boolean (value);
667 break;
669 case PROP_FULL_MODE:
670 agent->full_mode = g_value_get_boolean (value);
671 break;
673 case PROP_STUN_PACING_TIMER:
674 agent->timer_ta = g_value_get_uint (value);
675 break;
677 case PROP_MAX_CONNECTIVITY_CHECKS:
678 agent->max_conn_checks = g_value_get_uint (value);
679 break;
681 case PROP_PROXY_IP:
682 agent->proxy_ip = g_value_dup_string (value);
683 break;
685 case PROP_PROXY_PORT:
686 agent->proxy_port = g_value_get_uint (value);
687 break;
689 case PROP_PROXY_TYPE:
690 agent->proxy_type = g_value_get_uint (value);
691 break;
693 case PROP_PROXY_USERNAME:
694 agent->proxy_username = g_value_dup_string (value);
695 break;
697 case PROP_PROXY_PASSWORD:
698 agent->proxy_password = g_value_dup_string (value);
699 break;
701 default:
702 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
705 g_static_rec_mutex_unlock (&agent->mutex);
709 void agent_gathering_done (NiceAgent *agent)
712 GSList *i, *j, *k, *l, *m;
714 for (i = agent->streams; i; i = i->next) {
715 Stream *stream = i->data;
716 for (j = stream->components; j; j = j->next) {
717 Component *component = j->data;
719 for (k = component->local_candidates; k; k = k->next) {
720 NiceCandidate *local_candidate = k->data;
722 gchar tmpbuf[INET6_ADDRSTRLEN];
723 nice_address_to_string (&local_candidate->addr, tmpbuf);
724 nice_debug ("Agent %p: gathered local candidate : [%s]:%u"
725 " for s%d/c%d. U/P '%s'/'%s'", agent,
726 tmpbuf, nice_address_get_port (&local_candidate->addr),
727 local_candidate->stream_id, local_candidate->component_id,
728 local_candidate->username, local_candidate->password);
730 for (l = component->remote_candidates; l; l = l->next) {
731 NiceCandidate *remote_candidate = l->data;
733 for (m = stream->conncheck_list; m; m = m->next) {
734 CandidateCheckPair *p = m->data;
736 if (p->local == local_candidate && p->remote == remote_candidate)
737 break;
739 if (m == NULL) {
740 conn_check_add_for_candidate (agent, stream->id, component, remote_candidate);
747 agent_signal_gathering_done (agent);
750 void agent_signal_gathering_done (NiceAgent *agent)
752 GSList *i;
754 for (i = agent->streams; i; i = i->next) {
755 Stream *stream = i->data;
756 if (stream->gathering) {
757 stream->gathering = FALSE;
758 g_signal_emit (agent, signals[SIGNAL_CANDIDATE_GATHERING_DONE], 0, stream->id);
763 void agent_signal_initial_binding_request_received (NiceAgent *agent, Stream *stream)
765 if (stream->initial_binding_request_received != TRUE) {
766 stream->initial_binding_request_received = TRUE;
767 g_signal_emit (agent, signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED], 0, stream->id);
771 void agent_signal_new_selected_pair (NiceAgent *agent, guint stream_id, guint component_id, const gchar *local_foundation, const gchar *remote_foundation)
773 Component *component;
774 gchar *lf_copy;
775 gchar *rf_copy;
777 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
778 return;
780 lf_copy = g_strdup (local_foundation);
781 rf_copy = g_strdup (remote_foundation);
783 if (component->selected_pair.local->type == NICE_CANDIDATE_TYPE_RELAYED) {
784 nice_turn_socket_set_peer (component->selected_pair.local->sockptr,
785 &component->selected_pair.remote->addr);
788 g_signal_emit (agent, signals[SIGNAL_NEW_SELECTED_PAIR], 0,
789 stream_id, component_id, lf_copy, rf_copy);
791 g_free (lf_copy);
792 g_free (rf_copy);
795 void agent_signal_new_candidate (NiceAgent *agent, NiceCandidate *candidate)
797 g_signal_emit (agent, signals[SIGNAL_NEW_CANDIDATE], 0,
798 candidate->stream_id,
799 candidate->component_id,
800 candidate->foundation);
803 void agent_signal_new_remote_candidate (NiceAgent *agent, NiceCandidate *candidate)
805 g_signal_emit (agent, signals[SIGNAL_NEW_REMOTE_CANDIDATE], 0,
806 candidate->stream_id,
807 candidate->component_id,
808 candidate->foundation);
811 void agent_signal_component_state_change (NiceAgent *agent, guint stream_id, guint component_id, NiceComponentState state)
813 Component *component;
815 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
816 return;
818 if (component->state != state && state < NICE_COMPONENT_STATE_LAST) {
819 nice_debug ("Agent %p : stream %u component %u STATE-CHANGE %u -> %u.", agent,
820 stream_id, component_id, component->state, state);
822 component->state = state;
824 g_signal_emit (agent, signals[SIGNAL_COMPONENT_STATE_CHANGED], 0,
825 stream_id, component_id, state);
829 guint64
830 agent_candidate_pair_priority (NiceAgent *agent, NiceCandidate *local, NiceCandidate *remote)
832 if (agent->controlling_mode)
833 return nice_candidate_pair_priority (local->priority, remote->priority);
834 else
835 return nice_candidate_pair_priority (remote->priority, local->priority);
838 static gboolean
839 priv_add_new_candidate_discovery_stun (NiceAgent *agent,
840 NiceSocket *socket, NiceAddress server,
841 Stream *stream, guint component_id)
843 CandidateDiscovery *cdisco;
844 GSList *modified_list;
846 /* note: no need to check for redundant candidates, as this is
847 * done later on in the process */
849 cdisco = g_slice_new0 (CandidateDiscovery);
850 if (cdisco) {
851 modified_list = g_slist_append (agent->discovery_list, cdisco);
853 if (modified_list) {
854 cdisco->type = NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE;
855 cdisco->nicesock = socket;
856 cdisco->server = server;
857 cdisco->stream = stream;
858 cdisco->component = stream_find_component_by_id (stream, component_id);
859 cdisco->agent = agent;
860 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
861 STUN_COMPATIBILITY_RFC3489, 0);
863 nice_debug ("Agent %p : Adding new srv-rflx candidate discovery %p\n", agent, cdisco);
864 agent->discovery_list = modified_list;
865 ++agent->discovery_unsched_items;
868 return TRUE;
871 return FALSE;
874 static gboolean
875 priv_add_new_candidate_discovery_turn (NiceAgent *agent,
876 NiceSocket *socket, TurnServer *turn,
877 Stream *stream, guint component_id)
879 CandidateDiscovery *cdisco;
880 GSList *modified_list;
881 GSList *socket_modified_list;
883 /* note: no need to check for redundant candidates, as this is
884 * done later on in the process */
886 cdisco = g_slice_new0 (CandidateDiscovery);
887 if (cdisco) {
888 modified_list = g_slist_append (agent->discovery_list, cdisco);
890 if (modified_list) {
891 Component *component = stream_find_component_by_id (stream, component_id);
893 cdisco->type = NICE_CANDIDATE_TYPE_RELAYED;
895 if (turn->type == NICE_RELAY_TYPE_TURN_UDP) {
896 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
897 NiceAddress addr = socket->addr;
898 NiceSocket *new_socket;
899 nice_address_set_port (&addr, 0);
901 new_socket = nice_udp_bsd_socket_new (&addr);
902 if (new_socket) {
903 agent_attach_stream_component_socket (agent, stream,
904 component, new_socket);
905 socket_modified_list = g_slist_append (component->sockets, new_socket);
906 if (socket_modified_list) {
907 /* success: store a pointer to the sockaddr */
908 component->sockets = socket_modified_list;
909 socket = new_socket;
910 } else {
911 nice_socket_free (new_socket);
915 cdisco->nicesock = socket;
916 } else {
917 NiceAddress proxy_server;
918 socket = NULL;
920 if (agent->proxy_type != NICE_PROXY_TYPE_NONE &&
921 agent->proxy_ip != NULL &&
922 nice_address_set_from_string (&proxy_server, agent->proxy_ip)) {
923 nice_address_set_port (&proxy_server, agent->proxy_port);
924 socket = nice_tcp_bsd_socket_new (agent, component->ctx, &proxy_server);
926 if (socket) {
927 if (agent->proxy_type == NICE_PROXY_TYPE_SOCKS5) {
928 socket = nice_socks5_socket_new (socket, &turn->server,
929 agent->proxy_username, agent->proxy_password);
930 } else if (agent->proxy_type == NICE_PROXY_TYPE_HTTP){
931 socket = nice_http_socket_new (socket, &turn->server,
932 agent->proxy_username, agent->proxy_password);
933 } else {
934 /* TODO add HTTP support */
935 nice_socket_free (socket);
936 socket = NULL;
941 if (socket == NULL) {
942 socket = nice_tcp_bsd_socket_new (agent, component->ctx, &turn->server);
944 if (turn->type == NICE_RELAY_TYPE_TURN_TLS &&
945 agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
946 socket = nice_pseudossl_socket_new (agent, socket);
948 cdisco->nicesock = nice_tcp_turn_socket_new (agent, socket,
949 agent_to_turn_socket_compatibility (agent));
951 if (!cdisco->nicesock) {
952 agent->discovery_list = g_slist_remove (modified_list, cdisco);
953 g_slice_free (CandidateDiscovery, cdisco);
954 return FALSE;
957 agent_attach_stream_component_socket (agent, stream,
958 component, cdisco->nicesock);
959 socket_modified_list = g_slist_append (component->sockets, cdisco->nicesock);
960 if (socket_modified_list) {
961 /* success: store a pointer to the sockaddr */
962 component->sockets = socket_modified_list;
965 cdisco->turn = turn;
966 cdisco->server = turn->server;
968 cdisco->stream = stream;
969 cdisco->component = stream_find_component_by_id (stream, component_id);
970 cdisco->agent = agent;
972 if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
973 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
974 STUN_COMPATIBILITY_RFC3489,
975 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
976 STUN_AGENT_USAGE_IGNORE_CREDENTIALS);
977 } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
978 agent->compatibility == NICE_COMPATIBILITY_WLM2009) {
979 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
980 STUN_COMPATIBILITY_RFC3489,
981 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS);
982 } else {
983 stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES,
984 STUN_COMPATIBILITY_RFC5389,
985 STUN_AGENT_USAGE_ADD_SOFTWARE |
986 STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS);
989 nice_debug ("Agent %p : Adding new relay-rflx candidate discovery %p\n",
990 agent, cdisco);
991 agent->discovery_list = modified_list;
992 ++agent->discovery_unsched_items;
995 return TRUE;
998 return FALSE;
1001 NICEAPI_EXPORT guint
1002 nice_agent_add_stream (
1003 NiceAgent *agent,
1004 guint n_components)
1006 Stream *stream;
1007 GSList *modified_list = NULL;
1008 guint ret = 0;
1010 g_static_rec_mutex_lock (&agent->mutex);
1012 stream = stream_new (n_components);
1013 if (stream) {
1014 modified_list = g_slist_append (agent->streams, stream);
1015 if (modified_list) {
1016 stream->id = agent->next_stream_id++;
1017 nice_debug ("Agent %p : allocating stream id %u (%p)", agent, stream->id, stream);
1019 stream_initialize_credentials (stream, agent->rng);
1021 agent->streams = modified_list;
1023 else
1024 stream_free (stream);
1027 ret = stream->id;
1029 g_static_rec_mutex_unlock (&agent->mutex);
1030 return ret;
1034 NICEAPI_EXPORT gboolean
1035 nice_agent_set_relay_info(NiceAgent *agent,
1036 guint stream_id, guint component_id,
1037 const gchar *server_ip, guint server_port,
1038 const gchar *username, const gchar *password,
1039 NiceRelayType type)
1042 Component *component = NULL;
1044 g_return_val_if_fail (server_ip, FALSE);
1045 g_return_val_if_fail (server_port, FALSE);
1046 g_return_val_if_fail (username, FALSE);
1047 g_return_val_if_fail (password, FALSE);
1048 g_return_val_if_fail (type <= NICE_PROXY_TYPE_LAST, FALSE);
1050 g_static_rec_mutex_lock (&agent->mutex);
1052 if (agent_find_component (agent, stream_id, component_id, NULL, &component)) {
1053 TurnServer *turn = g_slice_new0 (TurnServer);
1054 nice_address_init (&turn->server);
1056 if (nice_address_set_from_string (&turn->server, server_ip)) {
1057 nice_address_set_port (&turn->server, server_port);
1058 } else {
1059 g_slice_free (TurnServer, turn);
1060 g_static_rec_mutex_unlock (&agent->mutex);
1061 return FALSE;
1065 turn->username = g_strdup (username);
1066 turn->password = g_strdup (password);
1067 turn->type = type;
1069 nice_debug ("Agent %p: added relay server [%s]:%d of type %d", agent,
1070 server_ip, server_port, type);
1072 component->turn_servers = g_list_append (component->turn_servers, turn);
1075 g_static_rec_mutex_unlock (&agent->mutex);
1076 return TRUE;
1080 NICEAPI_EXPORT void
1081 nice_agent_gather_candidates (
1082 NiceAgent *agent,
1083 guint stream_id)
1085 guint n;
1086 GSList *i;
1087 Stream *stream;
1089 g_static_rec_mutex_lock (&agent->mutex);
1091 stream = agent_find_stream (agent, stream_id);
1092 if (stream == NULL) {
1093 goto done;
1096 nice_debug ("Agent %p : In %s mode, starting candidate gathering.", agent,
1097 agent->full_mode ? "ICE-FULL" : "ICE-LITE");
1099 /* if no local addresses added, generate them ourselves */
1100 if (agent->local_addresses == NULL) {
1101 GList *addresses = nice_interfaces_get_local_ips (FALSE);
1102 GList *item;
1104 for (item = addresses; item; item = g_list_next (item)) {
1105 NiceAddress *addr = nice_address_new ();
1107 if (nice_address_set_from_string (addr, item->data)) {
1108 nice_agent_add_local_address (agent, addr);
1110 nice_address_free (addr);
1113 g_list_foreach (addresses, (GFunc) g_free, NULL);
1114 g_list_free (addresses);
1117 /* generate a local host candidate for each local address */
1118 for (i = agent->local_addresses; i; i = i->next){
1119 NiceAddress *addr = i->data;
1120 NiceCandidate *host_candidate;
1122 for (n = 0; n < stream->n_components; n++) {
1123 Component *component = stream_find_component_by_id (stream, n + 1);
1124 host_candidate = discovery_add_local_host_candidate (agent, stream->id,
1125 n + 1, addr);
1127 if (!host_candidate) {
1128 g_error ("No host candidate??");
1129 break;
1132 if (agent->full_mode &&
1133 agent->stun_server_ip) {
1134 NiceAddress stun_server;
1135 if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
1136 gboolean res;
1137 nice_address_set_port (&stun_server, agent->stun_server_port);
1139 res =
1140 priv_add_new_candidate_discovery_stun (agent,
1141 host_candidate->sockptr,
1142 stun_server,
1143 stream,
1144 n + 1);
1146 if (res != TRUE) {
1147 /* note: memory allocation failure, return error */
1148 g_error ("Memory allocation failure?");
1153 if (agent->full_mode && component) {
1154 GList *item;
1156 for (item = component->turn_servers; item; item = item->next) {
1157 TurnServer *turn = item->data;
1159 gboolean res =
1160 priv_add_new_candidate_discovery_turn (agent,
1161 host_candidate->sockptr,
1162 turn,
1163 stream,
1164 n + 1);
1166 if (res != TRUE) {
1167 /* note: memory allocation failure, return error */
1168 g_error ("Memory allocation failure?");
1175 stream->gathering = TRUE;
1178 /* note: no async discoveries pending, signal that we are ready */
1179 if (agent->discovery_unsched_items == 0) {
1180 nice_debug ("Agent %p: Candidate gathering FINISHED, no scheduled items.",
1181 agent);
1182 agent_gathering_done (agent);
1183 } else {
1184 g_assert (agent->discovery_list);
1185 discovery_schedule (agent);
1188 done:
1190 g_static_rec_mutex_unlock (&agent->mutex);
1193 static void priv_remove_keepalive_timer (NiceAgent *agent)
1195 if (agent->keepalive_timer_source != NULL) {
1196 g_source_destroy (agent->keepalive_timer_source);
1197 g_source_unref (agent->keepalive_timer_source);
1198 agent->keepalive_timer_source = NULL;
1202 NICEAPI_EXPORT void
1203 nice_agent_remove_stream (
1204 NiceAgent *agent,
1205 guint stream_id)
1207 /* note that streams/candidates can be in use by other threads */
1209 Stream *stream;
1210 GSList *i;
1212 g_static_rec_mutex_lock (&agent->mutex);
1213 stream = agent_find_stream (agent, stream_id);
1215 if (!stream) {
1216 goto done;
1219 /* note: remove items with matching stream_ids from both lists */
1220 conn_check_prune_stream (agent, stream);
1221 discovery_prune_stream (agent, stream_id);
1222 refresh_prune_stream (agent, stream_id);
1224 /* remove the stream itself */
1225 for (i = stream->components; i; i = i->next) {
1226 priv_detach_stream_component (stream, (Component *) i->data);
1229 agent->streams = g_slist_remove (agent->streams, stream);
1230 stream_free (stream);
1232 if (!agent->streams)
1233 priv_remove_keepalive_timer (agent);
1235 done:
1236 g_static_rec_mutex_unlock (&agent->mutex);
1239 NICEAPI_EXPORT gboolean
1240 nice_agent_add_local_address (NiceAgent *agent, NiceAddress *addr)
1242 NiceAddress *dup;
1243 GSList *modified_list;
1244 gboolean ret = FALSE;
1246 g_static_rec_mutex_lock (&agent->mutex);
1248 dup = nice_address_dup (addr);
1249 nice_address_set_port (dup, 0);
1250 modified_list = g_slist_append (agent->local_addresses, dup);
1251 if (modified_list) {
1252 agent->local_addresses = modified_list;
1254 ret = TRUE;
1255 goto done;
1258 done:
1259 g_static_rec_mutex_unlock (&agent->mutex);
1260 return ret;
1263 static gboolean priv_add_remote_candidate (
1264 NiceAgent *agent,
1265 guint stream_id,
1266 guint component_id,
1267 NiceCandidateType type,
1268 const NiceAddress *addr,
1269 const NiceAddress *base_addr,
1270 NiceCandidateTransport transport,
1271 guint32 priority,
1272 const gchar *username,
1273 const gchar *password,
1274 const gchar *foundation)
1276 Component *component;
1277 NiceCandidate *candidate;
1278 gboolean error_flag = FALSE;
1280 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
1281 return FALSE;
1283 /* step: check whether the candidate already exists */
1284 candidate = component_find_remote_candidate(component, addr, transport);
1285 if (candidate) {
1286 nice_debug ("Agent %p : Update existing remote candidate %p.", agent, candidate);
1287 /* case 1: an existing candidate, update the attributes */
1288 candidate->type = type;
1289 if (base_addr)
1290 candidate->base_addr = *base_addr;
1291 candidate->priority = priority;
1292 if (foundation)
1293 strncpy(candidate->foundation, foundation, NICE_CANDIDATE_MAX_FOUNDATION);
1294 /* note: username and password must remain the same during
1295 * a session; see sect 9.1.2 in ICE ID-19 */
1296 if (conn_check_add_for_candidate (agent, stream_id, component, candidate) < 0)
1297 error_flag = TRUE;
1299 else {
1300 /* case 2: add a new candidate */
1302 candidate = nice_candidate_new (type);
1303 if (candidate) {
1304 GSList *modified_list = g_slist_append (component->remote_candidates, candidate);
1305 if (modified_list) {
1306 component->remote_candidates = modified_list;
1308 candidate->stream_id = stream_id;
1309 candidate->component_id = component_id;
1311 candidate->type = type;
1312 if (addr)
1313 candidate->addr = *addr;
1315 gchar tmpbuf[INET6_ADDRSTRLEN];
1316 nice_address_to_string (addr, tmpbuf);
1317 nice_debug ("Agent %p : Adding remote candidate with addr [%s]:%u"
1318 " for s%d/c%d. U/P '%s'/'%s'", agent, tmpbuf,
1319 nice_address_get_port (addr), stream_id, component_id,
1320 username, password);
1323 if (base_addr)
1324 candidate->base_addr = *base_addr;
1326 candidate->transport = transport;
1327 candidate->priority = priority;
1328 candidate->username = g_strdup (username);
1329 candidate->password = g_strdup (password);
1331 if (foundation)
1332 g_strlcpy (candidate->foundation, foundation, NICE_CANDIDATE_MAX_FOUNDATION);
1334 if (conn_check_add_for_candidate (agent, stream_id, component, candidate) < 0)
1335 error_flag = TRUE;
1337 else /* memory alloc error: list insert */
1338 error_flag = TRUE;
1340 else /* memory alloc error: candidate creation */
1341 error_flag = TRUE;
1344 if (error_flag) {
1345 if (candidate)
1346 nice_candidate_free (candidate);
1347 return FALSE;
1350 return TRUE;
1353 NICEAPI_EXPORT gboolean
1354 nice_agent_set_remote_credentials (
1355 NiceAgent *agent,
1356 guint stream_id,
1357 const gchar *ufrag, const gchar *pwd)
1359 Stream *stream;
1360 gboolean ret = FALSE;
1362 g_static_rec_mutex_lock (&agent->mutex);
1364 stream = agent_find_stream (agent, stream_id);
1365 /* note: oddly enough, ufrag and pwd can be empty strings */
1366 if (stream && ufrag && pwd) {
1368 g_strlcpy (stream->remote_ufrag, ufrag, NICE_STREAM_MAX_UFRAG);
1369 g_strlcpy (stream->remote_password, pwd, NICE_STREAM_MAX_PWD);
1371 ret = TRUE;
1372 goto done;
1375 done:
1376 g_static_rec_mutex_unlock (&agent->mutex);
1377 return ret;
1381 NICEAPI_EXPORT gboolean
1382 nice_agent_get_local_credentials (
1383 NiceAgent *agent,
1384 guint stream_id,
1385 gchar **ufrag, gchar **pwd)
1387 Stream *stream;
1388 gboolean ret = TRUE;
1390 g_static_rec_mutex_lock (&agent->mutex);
1392 stream = agent_find_stream (agent, stream_id);
1393 if (stream == NULL) {
1394 goto done;
1397 if (!ufrag || !pwd) {
1398 goto done;
1401 *ufrag = g_strdup (stream->local_ufrag);
1402 *pwd = g_strdup (stream->local_password);
1403 ret = TRUE;
1405 done:
1407 g_static_rec_mutex_unlock (&agent->mutex);
1408 return ret;
1411 NICEAPI_EXPORT int
1412 nice_agent_set_remote_candidates (NiceAgent *agent, guint stream_id, guint component_id, const GSList *candidates)
1414 const GSList *i;
1415 int added = 0;
1416 Stream *stream;
1418 nice_debug ("Agent %p: set_remote_candidates %d %d", agent, stream_id, component_id);
1420 g_static_rec_mutex_lock (&agent->mutex);
1422 stream = agent_find_stream (agent, stream_id);
1423 if (stream == NULL) {
1424 added = -1;
1425 goto done;
1428 if (agent->discovery_unsched_items > 0 || stream->gathering) {
1429 nice_debug ("Agent %p: Remote candidates refused for stream %d because "
1430 "we are still gathering our own candidates", agent, stream_id);
1431 added = -1;
1432 goto done;
1435 for (i = candidates; i && added >= 0; i = i->next) {
1436 NiceCandidate *d = (NiceCandidate*) i->data;
1437 gboolean res =
1438 priv_add_remote_candidate (agent,
1439 stream_id,
1440 component_id,
1441 d->type,
1442 &d->addr,
1443 &d->base_addr,
1444 d->transport,
1445 d->priority,
1446 d->username,
1447 d->password,
1448 d->foundation);
1449 if (res)
1450 ++added;
1451 else
1452 added = -1;
1455 conn_check_remote_candidates_set(agent);
1457 if (added > 0) {
1458 gboolean res = conn_check_schedule_next (agent);
1459 if (res != TRUE)
1460 nice_debug ("Agent %p : Warning: unable to schedule any conn checks!", agent);
1463 done:
1464 g_static_rec_mutex_unlock (&agent->mutex);
1465 return added;
1469 static gint
1470 _nice_agent_recv (
1471 NiceAgent *agent,
1472 Stream *stream,
1473 Component *component,
1474 NiceSocket *socket,
1475 guint buf_len,
1476 gchar *buf)
1478 NiceAddress from;
1479 gint len;
1480 GList *item;
1482 len = nice_socket_recv (socket, &from, buf_len, buf);
1484 if (len <= 0)
1485 return len;
1487 #ifndef NDEBUG
1488 if (len > 0) {
1489 gchar tmpbuf[INET6_ADDRSTRLEN];
1490 nice_address_to_string (&from, tmpbuf);
1491 nice_debug ("Agent %p : Packet received on local socket %u from [%s]:%u (%u octets).", agent,
1492 socket->fileno, tmpbuf, nice_address_get_port (&from), len);
1494 #endif
1497 if ((guint)len > buf_len)
1499 /* buffer is not big enough to accept this packet */
1500 /* XXX: test this case */
1501 return 0;
1504 for (item = component->turn_servers; item; item = g_list_next (item)) {
1505 TurnServer *turn = item->data;
1506 if (nice_address_equal (&from, &turn->server)) {
1507 GSList * i = NULL;
1508 #ifndef NDEBUG
1509 nice_debug ("Agent %p : Packet received from TURN server candidate.",
1510 agent);
1511 #endif
1512 for (i = component->local_candidates; i; i = i->next) {
1513 NiceCandidate *cand = i->data;
1514 if (cand->type == NICE_CANDIDATE_TYPE_RELAYED &&
1515 cand->stream_id == stream->id &&
1516 cand->component_id == component->id) {
1517 len = nice_turn_socket_parse_recv (cand->sockptr, &socket,
1518 &from, len, buf, &from, buf, len);
1521 break;
1525 if (stun_message_validate_buffer_length ((uint8_t *) buf, (size_t) len) != len)
1526 /* If the retval is no 0, its not a valid stun packet, probably data */
1527 return len;
1530 if (conn_check_handle_inbound_stun (agent, stream, component, socket,
1531 &from, buf, len))
1532 /* handled STUN message*/
1533 return 0;
1535 /* unhandled STUN, pass to client */
1536 return len;
1540 NICEAPI_EXPORT gint
1541 nice_agent_send (
1542 NiceAgent *agent,
1543 guint stream_id,
1544 guint component_id,
1545 guint len,
1546 const gchar *buf)
1548 Stream *stream;
1549 Component *component;
1550 guint ret = -1;
1552 g_static_rec_mutex_lock (&agent->mutex);
1554 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1555 goto done;
1558 if (component->selected_pair.local != NULL)
1560 NiceSocket *sock;
1561 NiceAddress *addr;
1563 #ifndef NDEBUG
1564 gchar tmpbuf[INET6_ADDRSTRLEN];
1565 nice_address_to_string (&component->selected_pair.remote->addr, tmpbuf);
1567 nice_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", agent, stream_id, component_id,
1568 len, tmpbuf,
1569 nice_address_get_port (&component->selected_pair.remote->addr));
1570 #endif
1572 sock = component->selected_pair.local->sockptr;
1573 addr = &component->selected_pair.remote->addr;
1574 if (nice_socket_send (sock, addr, len, buf)) {
1575 ret = len;
1577 goto done;
1580 done:
1581 g_static_rec_mutex_unlock (&agent->mutex);
1582 return ret;
1586 NICEAPI_EXPORT GSList *
1587 nice_agent_get_local_candidates (
1588 NiceAgent *agent,
1589 guint stream_id,
1590 guint component_id)
1592 Component *component;
1593 GSList * ret = NULL;
1594 GSList * item = NULL;
1596 g_static_rec_mutex_lock (&agent->mutex);
1597 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
1599 goto done;
1602 for (item = component->local_candidates; item; item = item->next)
1603 ret = g_slist_append (ret, nice_candidate_copy (item->data));
1605 done:
1606 g_static_rec_mutex_unlock (&agent->mutex);
1607 return ret;
1611 NICEAPI_EXPORT GSList *
1612 nice_agent_get_remote_candidates (
1613 NiceAgent *agent,
1614 guint stream_id,
1615 guint component_id)
1617 Component *component;
1618 GSList *ret = NULL, *item = NULL;
1620 g_static_rec_mutex_lock (&agent->mutex);
1621 if (!agent_find_component (agent, stream_id, component_id, NULL, &component))
1623 goto done;
1626 for (item = component->remote_candidates; item; item = item->next)
1627 ret = g_slist_append (ret, nice_candidate_copy (item->data));
1629 done:
1630 g_static_rec_mutex_unlock (&agent->mutex);
1631 return ret;
1635 gboolean
1636 nice_agent_restart (
1637 NiceAgent *agent)
1639 GSList *i;
1640 gboolean res = TRUE;
1642 g_static_rec_mutex_lock (&agent->mutex);
1644 /* step: clean up all connectivity checks */
1645 conn_check_free (agent);
1647 /* step: regenerate tie-breaker value */
1648 priv_generate_tie_breaker (agent);
1650 for (i = agent->streams; i && res; i = i->next) {
1651 Stream *stream = i->data;
1653 /* step: reset local credentials for the stream and
1654 * clean up the list of remote candidates */
1655 res = stream_restart (stream, agent->rng);
1658 g_static_rec_mutex_unlock (&agent->mutex);
1659 return res;
1662 static void
1663 nice_agent_dispose (GObject *object)
1665 GSList *i;
1666 NiceAgent *agent = NICE_AGENT (object);
1668 /* step: free resources for the binding discovery timers */
1669 discovery_free (agent);
1670 g_assert (agent->discovery_list == NULL);
1671 refresh_free (agent);
1672 g_assert (agent->refresh_list == NULL);
1674 /* step: free resources for the connectivity check timers */
1675 conn_check_free (agent);
1677 priv_remove_keepalive_timer (agent);
1679 for (i = agent->local_addresses; i; i = i->next)
1681 NiceAddress *a = i->data;
1683 nice_address_free (a);
1686 g_slist_free (agent->local_addresses);
1687 agent->local_addresses = NULL;
1689 for (i = agent->streams; i; i = i->next)
1691 Stream *s = i->data;
1693 stream_free (s);
1696 g_slist_free (agent->streams);
1697 agent->streams = NULL;
1699 g_free (agent->stun_server_ip);
1700 agent->stun_server_ip = NULL;
1702 nice_rng_free (agent->rng);
1703 agent->rng = NULL;
1705 if (G_OBJECT_CLASS (nice_agent_parent_class)->dispose)
1706 G_OBJECT_CLASS (nice_agent_parent_class)->dispose (object);
1708 g_static_rec_mutex_free (&agent->mutex);
1712 typedef struct _IOCtx IOCtx;
1714 struct _IOCtx
1716 GIOChannel *channel;
1717 GSource *source;
1718 NiceAgent *agent;
1719 Stream *stream;
1720 Component *component;
1721 NiceSocket *socket;
1725 static IOCtx *
1726 io_ctx_new (
1727 NiceAgent *agent,
1728 Stream *stream,
1729 Component *component,
1730 NiceSocket *socket,
1731 GIOChannel *channel,
1732 GSource *source)
1734 IOCtx *ctx;
1736 ctx = g_slice_new0 (IOCtx);
1737 if (ctx) {
1738 ctx->agent = agent;
1739 ctx->stream = stream;
1740 ctx->component = component;
1741 ctx->socket = socket;
1742 ctx->channel = channel;
1743 ctx->source = source;
1745 return ctx;
1749 static void
1750 io_ctx_free (IOCtx *ctx)
1752 g_io_channel_unref (ctx->channel);
1753 g_slice_free (IOCtx, ctx);
1756 static gboolean
1757 nice_agent_g_source_cb (
1758 GIOChannel *io,
1759 G_GNUC_UNUSED
1760 GIOCondition condition,
1761 gpointer data)
1763 /* return value is whether to keep the source */
1765 IOCtx *ctx = data;
1766 NiceAgent *agent = ctx->agent;
1767 Stream *stream = ctx->stream;
1768 Component *component = ctx->component;
1769 gchar buf[MAX_BUFFER_SIZE];
1770 gint len;
1772 g_static_rec_mutex_lock (&agent->mutex);
1774 /* note: dear compiler, these are for you: */
1775 (void)io;
1777 len = _nice_agent_recv (agent, stream, component, ctx->socket,
1778 MAX_BUFFER_SIZE, buf);
1780 if (len > 0 && component->g_source_io_cb) {
1781 component->g_source_io_cb (agent, stream->id, component->id,
1782 len, buf, component->data);
1783 } else if (len < 0) {
1784 GSource *source = ctx->source;
1785 component->gsources = g_slist_remove (component->gsources, source);
1786 g_source_destroy (source);
1787 g_source_unref (source);
1788 /* We don't close the socket because it would be way too complicated to
1789 * take care of every path where the socket might still be used.. */
1790 nice_debug ("Agent %p: unable to recv from socket %p. Detaching", agent,
1791 ctx->socket);
1794 g_static_rec_mutex_unlock (&agent->mutex);
1795 return TRUE;
1799 * Attaches one socket handle to the main loop event context
1802 void
1803 agent_attach_stream_component_socket (NiceAgent *agent,
1804 Stream *stream,
1805 Component *component,
1806 NiceSocket *socket)
1808 GIOChannel *io;
1809 GSource *source;
1810 IOCtx *ctx;
1812 if (!component->ctx)
1813 return;
1815 io = g_io_channel_unix_new (socket->fileno);
1816 /* note: without G_IO_ERR the glib mainloop goes into
1817 * busyloop if errors are encountered */
1818 source = g_io_create_watch (io, G_IO_IN | G_IO_ERR);
1819 ctx = io_ctx_new (agent, stream, component, socket, io, source);
1820 g_source_set_callback (source, (GSourceFunc) nice_agent_g_source_cb,
1821 ctx, (GDestroyNotify) io_ctx_free);
1822 nice_debug ("Agent %p : Attach source %p (stream %u).", agent, source, stream->id);
1823 g_source_attach (source, component->ctx);
1824 component->gsources = g_slist_append (component->gsources, source);
1829 * Attaches socket handles of 'stream' to the main eventloop
1830 * context.
1833 static gboolean
1834 priv_attach_stream_component (NiceAgent *agent,
1835 Stream *stream,
1836 Component *component)
1838 GSList *i;
1840 for (i = component->sockets; i; i = i->next)
1841 agent_attach_stream_component_socket (agent, stream, component, i->data);
1843 return TRUE;
1847 * Detaches socket handles of 'stream' from the main eventloop
1848 * context.
1851 static void priv_detach_stream_component (Stream *stream, Component *component)
1853 GSList *i;
1855 for (i = component->gsources; i; i = i->next) {
1856 GSource *source = i->data;
1857 nice_debug ("Detach source %p (stream %u).", source, stream->id);
1858 g_source_destroy (source);
1859 g_source_unref (source);
1862 g_slist_free (component->gsources);
1863 component->gsources = NULL;
1866 NICEAPI_EXPORT gboolean
1867 nice_agent_attach_recv (
1868 NiceAgent *agent,
1869 guint stream_id,
1870 guint component_id,
1871 GMainContext *ctx,
1872 NiceAgentRecvFunc func,
1873 gpointer data)
1875 Component *component = NULL;
1876 Stream *stream = NULL;
1877 gboolean ret = FALSE;
1879 g_static_rec_mutex_lock (&agent->mutex);
1881 /* attach candidates */
1883 /* step: check that params specify an existing pair */
1884 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1885 g_warning ("Could not find component %u in stream %u", component_id,
1886 stream_id);
1887 goto done;
1890 if (component->g_source_io_cb && func == NULL)
1891 priv_detach_stream_component (stream, component);
1893 ret = TRUE;
1895 if (func && ctx) {
1896 component->g_source_io_cb = func;
1897 component->data = data;
1898 component->ctx = ctx;
1899 priv_attach_stream_component (agent, stream, component);
1900 } else {
1901 component->g_source_io_cb = NULL;
1902 component->data = NULL;
1903 component->ctx = NULL;
1907 done:
1908 g_static_rec_mutex_unlock (&agent->mutex);
1909 return ret;
1912 NICEAPI_EXPORT gboolean
1913 nice_agent_set_selected_pair (
1914 NiceAgent *agent,
1915 guint stream_id,
1916 guint component_id,
1917 const gchar *lfoundation,
1918 const gchar *rfoundation)
1920 Component *component;
1921 Stream *stream;
1922 CandidatePair pair;
1923 gboolean ret = FALSE;
1925 g_static_rec_mutex_lock (&agent->mutex);
1927 /* step: check that params specify an existing pair */
1928 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1929 goto done;
1932 if (!component_find_pair (component, agent, lfoundation, rfoundation, &pair)){
1933 goto done;
1936 /* step: stop connectivity checks (note: for the whole stream) */
1937 conn_check_prune_stream (agent, stream);
1939 /* step: change component state */
1940 agent_signal_component_state_change (agent, stream_id, component_id, NICE_COMPONENT_STATE_READY);
1942 /* step: set the selected pair */
1943 component_update_selected_pair (component, &pair);
1944 agent_signal_new_selected_pair (agent, stream_id, component_id, lfoundation, rfoundation);
1946 ret = TRUE;
1948 done:
1949 g_static_rec_mutex_unlock (&agent->mutex);
1950 return ret;
1954 GSource* agent_timeout_add_with_context (NiceAgent *agent, guint interval,
1955 GSourceFunc function, gpointer data)
1957 GSource *source;
1958 guint id;
1960 g_return_val_if_fail (function != NULL, 0);
1962 source = g_timeout_source_new (interval);
1964 g_source_set_callback (source, function, data, NULL);
1965 id = g_source_attach (source, agent->main_context);
1967 return source;
1971 NICEAPI_EXPORT gboolean
1972 nice_agent_set_selected_remote_candidate (
1973 NiceAgent *agent,
1974 guint stream_id,
1975 guint component_id,
1976 NiceCandidate *candidate)
1978 Component *component;
1979 Stream *stream;
1980 NiceCandidate *lcandidate = NULL;
1981 gboolean ret = FALSE;
1983 g_static_rec_mutex_lock (&agent->mutex);
1985 /* step: check if the component exists*/
1986 if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) {
1987 goto done;
1990 /* step: stop connectivity checks (note: for the whole stream) */
1991 conn_check_prune_stream (agent, stream);
1994 /* step: set the selected pair */
1995 lcandidate = component_set_selected_remote_candidate (agent, component,
1996 candidate);
1997 if (!lcandidate)
1998 goto done;
2000 /* step: change component state */
2001 agent_signal_component_state_change (agent, stream_id, component_id, NICE_COMPONENT_STATE_READY);
2003 agent_signal_new_selected_pair (agent, stream_id, component_id,
2004 lcandidate->foundation,
2005 candidate->foundation);
2007 ret = TRUE;
2009 done:
2010 g_static_rec_mutex_unlock (&agent->mutex);
2011 return ret;