fix comment
[sipe-libnice.git] / agent / agent.c
blob5d267d26401d72f50126e2910073654053d8aeea
2 #include <string.h>
4 #include <sys/select.h>
6 #include <glib.h>
8 #include "stun.h"
9 #include "udp.h"
10 #include "random.h"
11 #include "agent.h"
12 #include "agent-signals-marshal.h"
15 /*** component ***/
18 /* (ICE-13 §4.1.1) For RTP-based media streams, the RTP itself has a component
19 * ID of 1, and RTCP a component ID of 2. If an agent is using RTCP it MUST
20 * obtain a candidate for it. If an agent is using both RTP and RTCP, it
21 * would end up with 2*K host candidates if an agent has K interfaces.
24 typedef enum
26 COMPONENT_TYPE_RTP,
27 COMPONENT_TYPE_RTCP,
28 } ComponentType;
31 typedef struct _Component Component;
33 struct _Component
35 ComponentType type;
36 /* the local candidate that last received a valid connectivity check */
37 NiceCandidate *active_candidate;
38 /* the remote address that the last connectivity check came from */
39 NiceAddress peer_addr;
40 guint id;
41 NiceComponentState state;
42 GSList *local_candidates;
43 GSList *remote_candidates;
47 static Component *
48 component_new (
49 G_GNUC_UNUSED
50 ComponentType type)
52 Component *component;
54 component = g_slice_new0 (Component);
55 component->id = 1;
56 return component;
60 static void
61 component_free (Component *cmp)
63 GSList *i;
65 for (i = cmp->local_candidates; i; i = i->next)
67 NiceCandidate *candidate = i->data;
69 nice_candidate_free (candidate);
72 for (i = cmp->remote_candidates; i; i = i->next)
74 NiceCandidate *candidate = i->data;
76 nice_candidate_free (candidate);
79 g_slist_free (cmp->local_candidates);
80 g_slist_free (cmp->remote_candidates);
81 g_slice_free (Component, cmp);
85 /*** stream ***/
88 typedef struct _Stream Stream;
90 struct _Stream
92 guint id;
93 /* XXX: streams can have multiple components */
94 Component *component;
98 static Stream *
99 stream_new (void)
101 Stream *stream;
103 stream = g_slice_new0 (Stream);
104 stream->component = component_new (COMPONENT_TYPE_RTP);
105 return stream;
109 static void
110 stream_free (Stream *stream)
112 component_free (stream->component);
113 g_slice_free (Stream, stream);
117 /*** candidate_pair ***/
120 typedef struct _CandidatePair CandidatePair;
122 struct _CandidatePair
124 NiceCandidate local;
125 NiceCandidate remote;
129 /* ICE-13 §5.7 (p24) */
130 typedef enum
132 CHECK_STATE_WAITING,
133 CHECK_STATE_IN_PROGRESS,
134 CHECK_STATE_SUCCEEDED,
135 CHECK_STATE_FAILED,
136 CHECK_STATE_FROZEN,
137 } CheckState;
140 typedef enum
142 CHECK_LIST_STATE_RUNNING,
143 CHECK_LIST_STATE_COMPLETED,
144 } CheckListState;
147 #if 0
148 /* ICE-13 §5.7 */
149 guint64
150 candidate_pair_priority (
151 guint64 offerer_prio,
152 guint64 answerer_prio)
154 return (
155 0x100000000LL * MIN (offerer_prio, answerer_prio) +
156 2 * MAX (offerer_prio, answerer_prio) +
157 (offerer_prio > answerer_prio ? 1 : 0));
159 #endif
162 /*** agent ***/
165 G_DEFINE_TYPE (NiceAgent, nice_agent, G_TYPE_OBJECT);
168 enum
170 PROP_SOCKET_FACTORY = 1,
174 enum
176 SIGNAL_COMPONENT_STATE_CHANGED,
177 N_SIGNALS,
181 static guint signals[N_SIGNALS];
184 static Stream *
185 find_stream (NiceAgent *agent, guint stream_id)
187 GSList *i;
189 for (i = agent->streams; i; i = i->next)
191 Stream *s = i->data;
193 if (s->id == stream_id)
194 return s;
197 return NULL;
201 static gboolean
202 find_component (
203 NiceAgent *agent,
204 guint stream_id,
205 guint component_id,
206 Stream **stream,
207 Component **component)
209 Stream *s;
211 if (component_id != 1)
212 return FALSE;
214 s = find_stream (agent, stream_id);
216 if (s == NULL)
217 return FALSE;
219 if (stream)
220 *stream = s;
222 if (component)
223 *component = s->component;
225 return TRUE;
229 static void
230 nice_agent_dispose (GObject *object);
232 static void
233 nice_agent_get_property (
234 GObject *object,
235 guint property_id,
236 GValue *value,
237 GParamSpec *pspec);
239 static void
240 nice_agent_set_property (
241 GObject *object,
242 guint property_id,
243 const GValue *value,
244 GParamSpec *pspec);
247 static void
248 nice_agent_class_init (NiceAgentClass *klass)
250 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
252 gobject_class->get_property = nice_agent_get_property;
253 gobject_class->set_property = nice_agent_set_property;
254 gobject_class->dispose = nice_agent_dispose;
256 /* install properties */
258 g_object_class_install_property (gobject_class, PROP_SOCKET_FACTORY,
259 g_param_spec_pointer (
260 "socket-factory",
261 "UDP socket factory",
262 "The socket factory used to create new UDP sockets",
263 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
265 /* install signals */
267 signals[SIGNAL_COMPONENT_STATE_CHANGED] =
268 g_signal_new (
269 "component-state-changed",
270 G_OBJECT_CLASS_TYPE (klass),
271 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
273 NULL,
274 NULL,
275 agent_marshal_VOID__UINT_UINT_UINT,
276 G_TYPE_NONE,
278 G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
279 G_TYPE_INVALID);
283 static void
284 nice_agent_init (NiceAgent *agent)
286 agent->next_candidate_id = 1;
287 agent->next_stream_id = 1;
292 * nice_agent_new:
293 * @factory: a NiceUDPSocketFactory used for allocating sockets
295 * Create a new NiceAgent.
297 * Returns: the new agent
299 NiceAgent *
300 nice_agent_new (NiceUDPSocketFactory *factory)
302 return g_object_new (NICE_TYPE_AGENT,
303 "socket-factory", factory,
304 NULL);
308 static void
309 nice_agent_get_property (
310 GObject *object,
311 guint property_id,
312 GValue *value,
313 GParamSpec *pspec)
315 NiceAgent *agent = NICE_AGENT (object);
317 switch (property_id)
319 case PROP_SOCKET_FACTORY:
320 g_value_set_pointer (value, agent->socket_factory);
321 break;
323 default:
324 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
329 static void
330 nice_agent_set_property (
331 GObject *object,
332 guint property_id,
333 const GValue *value,
334 GParamSpec *pspec)
336 NiceAgent *agent = NICE_AGENT (object);
338 switch (property_id)
340 case PROP_SOCKET_FACTORY:
341 agent->socket_factory = g_value_get_pointer (value);
342 break;
344 default:
345 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
350 static void
351 nice_agent_add_local_host_candidate (
352 NiceAgent *agent,
353 guint stream_id,
354 guint component_id,
355 NiceAddress *address)
357 NiceRNG *rng;
358 NiceCandidate *candidate;
359 Component *component;
361 if (!find_component (agent, stream_id, component_id, NULL, &component))
362 return;
364 candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_HOST);
365 candidate->id = agent->next_candidate_id++;
366 candidate->stream_id = stream_id;
367 candidate->component_id = component_id;
368 candidate->addr = *address;
369 candidate->base_addr = *address;
370 component->local_candidates = g_slist_append (component->local_candidates,
371 candidate);
373 /* generate username/password */
374 rng = nice_rng_new ();
375 nice_rng_generate_bytes_print (rng, 8, candidate->username);
376 nice_rng_generate_bytes_print (rng, 8, candidate->password);
377 nice_rng_free (rng);
379 /* allocate socket */
380 /* XXX: handle error */
381 if (!nice_udp_socket_factory_make (agent->socket_factory,
382 &(candidate->sock), address))
383 g_assert_not_reached ();
385 candidate->addr = candidate->sock.addr;
386 candidate->base_addr = candidate->sock.addr;
391 * nice_agent_add_stream:
392 * @agent: a NiceAgent
393 * @handle_recv: a function called when the stream recieves data
394 * @handle_recv_data: data passed as last parameter to @handle_recv
396 * Add a data stream to @agent.
398 * Returns: the ID of the new stream
400 guint
401 nice_agent_add_stream (
402 NiceAgent *agent,
403 guint n_components)
405 Stream *stream;
406 GSList *i;
408 g_assert (n_components == 1);
409 stream = stream_new ();
410 stream->id = agent->next_stream_id++;
411 agent->streams = g_slist_append (agent->streams, stream);
413 /* generate a local host candidate for each local address */
415 for (i = agent->local_addresses; i; i = i->next)
417 NiceAddress *addr = i->data;
419 nice_agent_add_local_host_candidate (agent, stream->id,
420 stream->component->id, addr);
422 /* XXX: need to check for redundant candidates? */
423 /* later: send STUN requests to obtain server-reflexive candidates */
426 return stream->id;
431 * nice_agent_remove_stream:
432 * @agent: a NiceAgent
433 * @stream_id: the ID of the stream to remove
435 void
436 nice_agent_remove_stream (
437 NiceAgent *agent,
438 guint stream_id)
440 /* note that streams/candidates can be in use by other threads */
442 Stream *stream;
444 stream = find_stream (agent, stream_id);
446 if (!stream)
447 return;
449 /* remove stream */
451 stream_free (stream);
452 agent->streams = g_slist_remove (agent->streams, stream);
457 * nice_agent_add_local_address:
458 * @agent: A NiceAgent
459 * @addr: the address of a local IP interface
461 * Inform the agent of the presence of an address that a local network
462 * interface is bound to.
464 void
465 nice_agent_add_local_address (NiceAgent *agent, NiceAddress *addr)
467 NiceAddress *dup;
469 dup = nice_address_dup (addr);
470 dup->port = 0;
471 agent->local_addresses = g_slist_append (agent->local_addresses, dup);
473 /* XXX: Should we generate local candidates for existing streams at this
474 * point, or require that local addresses are set before media streams are
475 * added?
480 * nice_agent_add_remote_candidate
481 * @agent: a NiceAgent
482 * @stream_id: the ID of the stream the candidate is for
483 * @component_id: the ID of the component the candidate is for
484 * @type: the type of the new candidate
485 * @addr: the new candidate's IP address
486 * @port: the new candidate's port
487 * @username: the new candidate's username
488 * @password: the new candidate's password
490 * Add a candidate our peer has informed us about to the agent's list.
492 void
493 nice_agent_add_remote_candidate (
494 NiceAgent *agent,
495 guint stream_id,
496 guint component_id,
497 NiceCandidateType type,
498 NiceAddress *addr,
499 const gchar *username,
500 const gchar *password)
502 NiceCandidate *candidate;
503 Component *component;
505 if (!find_component (agent, stream_id, component_id, NULL, &component))
506 return;
508 candidate = nice_candidate_new (type);
509 candidate->stream_id = stream_id;
510 candidate->component_id = component_id;
511 /* XXX: do remote candidates need IDs? */
512 candidate->id = 0;
513 candidate->addr = *addr;
514 strncpy (candidate->username, username, sizeof (candidate->username));
515 strncpy (candidate->password, password, sizeof (candidate->password));
517 component->remote_candidates = g_slist_append (component->remote_candidates,
518 candidate);
520 /* later: for each component, generate a new check with the new candidate */
524 #if 0
525 static NiceCandidate *
526 _local_candidate_lookup (NiceAgent *agent, guint candidate_id)
528 GSList *i;
530 for (i = agent->local_candidates; i; i = i->next)
532 NiceCandidate *c = i->data;
534 if (c->id == candidate_id)
535 return c;
538 return NULL;
540 #endif
543 static NiceCandidate *
544 find_candidate_by_fd (Component *component, guint fd)
546 GSList *i;
548 for (i = component->local_candidates; i; i = i->next)
550 NiceCandidate *c = i->data;
552 if (c->sock.fileno == fd)
553 return c;
556 return NULL;
560 static void
561 _handle_stun_binding_request (
562 NiceAgent *agent,
563 Stream *stream,
564 Component *component,
565 NiceCandidate *local,
566 NiceAddress from,
567 StunMessage *msg)
569 GSList *i;
570 StunAttribute **attr;
571 gchar *username = NULL;
572 NiceCandidate *remote = NULL;
574 /* msg should have either:
576 * Jingle P2P:
577 * username = local candidate username + remote candidate username
578 * ICE:
579 * username = local candidate username + ":" + remote candidate username
580 * password = local candidate pwd
581 * priority = priority to use if a new candidate is generated
583 * Note that:
585 * - "local"/"remote" are from the perspective of the receiving side
586 * - the remote candidate username is not necessarily unique; Jingle seems
587 * to always generate a unique username/password for each candidate, but
588 * ICE makes no guarantees
590 * There are three cases we need to deal with:
592 * - valid username with a known address
593 * --> send response
594 * - valid username with an unknown address
595 * --> send response
596 * --> later: create new remote candidate
597 * - invalid username
598 * --> send error
601 if (msg->attributes)
602 for (attr = msg->attributes; *attr; attr++)
603 if ((*attr)->type == STUN_ATTRIBUTE_USERNAME)
605 username = (*attr)->username;
606 break;
609 if (username == NULL)
610 /* no username attribute found */
611 goto ERROR;
613 /* validate username */
614 /* XXX: Should first try and find a remote candidate with a matching
615 * transport address, and fall back to matching on username only after that.
616 * That way, we know to always generate a new remote candidate if the
617 * transport address didn't match.
620 for (i = component->remote_candidates; i; i = i->next)
622 guint len;
624 remote = i->data;
626 #if 0
627 g_debug ("uname check: %s :: %s -- %s", username, local->username,
628 remote->username);
629 #endif
631 if (!g_str_has_prefix (username, local->username))
632 continue;
634 len = strlen (local->username);
636 if (0 != strcmp (username + len, remote->username))
637 continue;
639 #if 0
640 /* usernames match; check address */
642 if (rtmp->addr.addr_ipv4 == ntohs (from.sin_addr.s_addr) &&
643 rtmp->port == ntohl (from.sin_port))
645 /* this is a candidate we know about, just send a reply */
646 /* is candidate pair active now? */
647 remote = rtmp;
649 #endif
651 /* send response */
652 goto RESPOND;
655 /* username is not valid */
656 goto ERROR;
658 RESPOND:
660 #ifdef DEBUG
662 gchar *ip;
664 ip = nice_address_to_string (&remote->addr);
665 g_debug ("s%d:%d: got valid connectivity check for candidate %d (%s:%d)",
666 stream->id, component->id, remote->id, ip, remote->addr.port);
667 g_free (ip);
669 #endif
671 /* update candidate/peer affinity */
672 /* Note that @from might be different to @remote->addr; for ICE, this
673 * (always?) creates a new peer-reflexive remote candidate (§7.2).
675 /* XXX: test case where @from != @remote->addr. */
677 component->active_candidate = local;
678 component->peer_addr = from;
680 /* send STUN response */
683 StunMessage *response;
684 guint len;
685 gchar *packed;
687 response = stun_message_new (STUN_MESSAGE_BINDING_RESPONSE,
688 msg->transaction_id, 2);
689 response->attributes[0] = stun_attribute_mapped_address_new (
690 from.addr_ipv4, from.port);
691 response->attributes[1] = stun_attribute_username_new (username);
692 len = stun_message_pack (response, &packed);
693 nice_udp_socket_send (&local->sock, &from, len, packed);
695 g_free (packed);
696 stun_message_free (response);
699 /* send reciprocal ("triggered") connectivity check */
700 /* XXX: possibly we shouldn't do this if we're being an ICE Lite agent */
703 NiceRNG *rng;
704 StunMessage *extra;
705 gchar *username;
706 guint len;
707 gchar *packed;
709 extra = stun_message_new (STUN_MESSAGE_BINDING_REQUEST,
710 NULL, 1);
712 username = g_strconcat (remote->username, local->username, NULL);
713 extra->attributes[0] = stun_attribute_username_new (username);
714 g_free (username);
716 rng = nice_rng_new ();
717 nice_rng_generate_bytes (rng, 16, extra->transaction_id);
718 nice_rng_free (rng);
720 len = stun_message_pack (extra, &packed);
721 nice_udp_socket_send (&local->sock, &from, len, packed);
722 g_free (packed);
724 stun_message_free (extra);
727 /* emit component-state-changed(connected) */
728 /* XXX: probably better do this when we get the binding response */
731 if (component->state != NICE_COMPONENT_STATE_CONNECTED)
733 component->state = NICE_COMPONENT_STATE_CONNECTED;
734 g_signal_emit (agent, signals[SIGNAL_COMPONENT_STATE_CHANGED], 0,
735 stream->id, component->id, component->state);
739 return;
741 ERROR:
743 #ifdef DEBUG
745 gchar *ip;
747 ip = nice_address_to_string (&remote->addr);
748 g_debug (
749 "s%d:%d: got invalid connectivity check for candidate %d (%s:%d)",
750 stream->id, component->id, remote->id, ip, remote->addr.port);
751 g_free (ip);
753 #endif
755 /* XXX: add ERROR-CODE parameter */
758 StunMessage *response;
759 guint len;
760 gchar *packed;
762 response = stun_message_new (STUN_MESSAGE_BINDING_ERROR_RESPONSE,
763 msg->transaction_id, 0);
764 len = stun_message_pack (response, &packed);
765 nice_udp_socket_send (&local->sock, &from, len, packed);
767 g_free (packed);
768 stun_message_free (response);
771 /* XXX: we could be clever and keep around STUN packets that we couldn't
772 * validate, then re-examine them when we get new remote candidates -- would
773 * this fix some timing problems (i.e. TCP being slower than UDP)
775 /* XXX: if the peer is the controlling agent, it may include a USE-CANDIDATE
776 * attribute in the binding request
781 static void
782 _handle_stun (
783 NiceAgent *agent,
784 Stream *stream,
785 Component *component,
786 NiceCandidate *local,
787 NiceAddress from,
788 StunMessage *msg)
790 switch (msg->type)
792 case STUN_MESSAGE_BINDING_REQUEST:
793 _handle_stun_binding_request (agent, stream, component, local, from,
794 msg);
795 break;
796 case STUN_MESSAGE_BINDING_RESPONSE:
797 /* XXX: check it matches a request we sent */
798 break;
799 default:
800 /* a message type we don't know how to handle */
801 /* XXX: send error response */
802 break;
807 static guint
808 _nice_agent_recv (
809 NiceAgent *agent,
810 Stream *stream,
811 Component *component,
812 NiceCandidate *candidate,
813 guint buf_len,
814 gchar *buf)
816 NiceAddress from;
817 guint len;
819 len = nice_udp_socket_recv (&(candidate->sock), &from,
820 buf_len, buf);
822 if (len == 0)
823 return 0;
825 g_assert (len < buf_len);
827 /* XXX: verify sender; maybe:
829 * if (candidate->other != NULL)
831 * if (from != candidate->other.addr)
832 * // ignore packet from unexpected sender
833 * return;
835 * else
837 * // go through remote candidates, looking for one matching packet from
838 * // address; if found, assign it to candidate->other and call handler,
839 * // otherwise ignore it
842 * Perhaps remote socket affinity is superfluous and all we need is the
843 * second part.
844 * Perhaps we should also check whether this candidate is supposed to be
845 * active.
848 /* The top two bits of an RTP message are the version number; the current
849 * version number is 2. The top two bits of a STUN message are always 0.
852 if ((buf[0] & 0xc0) == 0x80)
854 /* looks like RTP */
855 return len;
857 else if ((buf[0] & 0xc0) == 0)
859 /* looks like a STUN message (connectivity check) */
860 /* connectivity checks are described in ICE-13 §7. */
861 StunMessage *msg;
863 msg = stun_message_unpack (len, buf);
865 if (msg != NULL)
867 _handle_stun (agent, stream, component, candidate, from, msg);
868 stun_message_free (msg);
872 /* anything else is ignored */
873 return 0;
878 * nice_agent_recv:
879 * @agent: a NiceAgent
880 * @stream_id: the ID of the stream to recieve data from
881 * @component_id: the ID of the component to receive data from
882 * @buf_len: the size of @buf
883 * @buf: the buffer to read data into
885 * Recieve data on a particular component.
887 * Returns: the amount of data read into @buf
889 guint
890 nice_agent_recv (
891 NiceAgent *agent,
892 guint stream_id,
893 guint component_id,
894 guint buf_len,
895 gchar *buf)
897 guint len = 0;
898 fd_set fds;
899 guint max_fd = 0;
900 gint num_readable;
901 GSList *i;
902 Stream *stream;
903 Component *component;
905 if (!find_component (agent, stream_id, component_id, &stream, &component))
906 return 0;
908 FD_ZERO (&fds);
910 for (i = component->local_candidates; i; i = i->next)
912 NiceCandidate *candidate = i->data;
914 FD_SET (candidate->sock.fileno, &fds);
915 max_fd = MAX (candidate->sock.fileno, max_fd);
918 /* Loop on candidate sockets until we find one that has non-STUN data
919 * waiting on it.
922 for (;;)
924 num_readable = select (max_fd + 1, &fds, NULL, NULL, NULL);
925 g_assert (num_readable >= 0);
927 if (num_readable > 0)
929 guint j;
931 for (j = 0; j <= max_fd; j++)
932 if (FD_ISSET (j, &fds))
934 NiceCandidate *candidate;
936 candidate = find_candidate_by_fd (component, j);
937 g_assert (candidate);
938 len = _nice_agent_recv (agent, stream, component, candidate,
939 buf_len, buf);
941 if (len > 0)
942 return len;
947 g_assert_not_reached ();
951 guint
952 nice_agent_recv_sock (
953 NiceAgent *agent,
954 guint stream_id,
955 guint component_id,
956 guint sock,
957 guint buf_len,
958 gchar *buf)
960 NiceCandidate *candidate;
961 Stream *stream;
962 Component *component;
964 if (!find_component (agent, stream_id, component_id, &stream, &component))
965 return 0;
967 candidate = find_candidate_by_fd (component, sock);
968 g_assert (candidate);
970 return _nice_agent_recv (agent, stream, stream->component,
971 candidate, buf_len, buf);
976 * nice_agent_poll_read:
977 * @agent: A NiceAgent
978 * @other_fds: A GSList of other file descriptors to poll
980 * Polls the agent's sockets until at least one of them is readable, and
981 * additionally if @other_fds is not NULL, polls those for readability too.
982 * @other_fds should contain the file descriptors directly, i.e. using
983 * GUINT_TO_POINTER.
985 * Returns: A list of file descriptors from @other_fds that are readable
987 GSList *
988 nice_agent_poll_read (
989 NiceAgent *agent,
990 GSList *other_fds,
991 NiceAgentRecvFunc func,
992 gpointer data)
994 fd_set fds;
995 guint max_fd = 0;
996 gint num_readable;
997 GSList *ret = NULL;
998 GSList *i;
999 guint j;
1001 FD_ZERO (&fds);
1003 for (i = agent->streams; i; i = i->next)
1005 GSList *j;
1006 Stream *stream = i->data;
1007 Component *component = stream->component;
1009 for (j = component->local_candidates; j; j = j->next)
1011 NiceCandidate *candidate = j->data;
1013 FD_SET (candidate->sock.fileno, &fds);
1014 max_fd = MAX (candidate->sock.fileno, max_fd);
1018 for (i = other_fds; i; i = i->next)
1020 guint fileno;
1022 fileno = GPOINTER_TO_UINT (i->data);
1023 FD_SET (fileno, &fds);
1024 max_fd = MAX (fileno, max_fd);
1027 num_readable = select (max_fd + 1, &fds, NULL, NULL, NULL);
1029 if (num_readable < 1)
1030 /* none readable, or error */
1031 return NULL;
1033 for (j = 0; j <= max_fd; j++)
1034 if (FD_ISSET (j, &fds))
1036 if (g_slist_find (other_fds, GUINT_TO_POINTER (j)))
1037 ret = g_slist_append (ret, GUINT_TO_POINTER (j));
1038 else
1040 NiceCandidate *candidate = NULL;
1041 Stream *stream;
1042 gchar buf[1024];
1043 guint len;
1045 for (i = agent->streams; i; i = i->next)
1047 Stream *s = i->data;
1048 Component *c = s->component;
1050 candidate = find_candidate_by_fd (c, j);
1052 if (candidate != NULL)
1053 break;
1056 if (candidate == NULL)
1057 break;
1059 stream = find_stream (agent, candidate->stream_id);
1061 if (stream == NULL)
1062 break;
1064 len = _nice_agent_recv (agent, stream, stream->component,
1065 candidate, 1024, buf);
1067 if (len && func != NULL)
1068 func (agent, stream->id, candidate->component_id, len, buf,
1069 data);
1073 return ret;
1077 void
1078 nice_agent_send (
1079 NiceAgent *agent,
1080 guint stream_id,
1081 guint component_id,
1082 guint len,
1083 const gchar *buf)
1085 Stream *stream;
1086 Component *component;
1088 stream = find_stream (agent, stream_id);
1089 component = stream->component;
1091 if (component->active_candidate != NULL)
1093 NiceUDPSocket *sock;
1094 NiceAddress *addr;
1096 #if 0
1097 g_debug ("s%d:%d: sending %d bytes to %08x:%d", stream_id, component_id,
1098 len, component->peer_addr->addr_ipv4, component->peer_addr->port);
1099 #endif
1101 sock = &component->active_candidate->sock;
1102 addr = &component->peer_addr;
1103 nice_udp_socket_send (sock, addr, len, buf);
1109 * Set the STUN server from which to obtain server-reflexive candidates.
1112 void
1113 nice_agent_set_stun_server (
1114 NiceAgent *agent,
1115 NiceAddress *addr)
1122 * nice_agent_get_local_candidates:
1123 * @agent: A NiceAgent
1125 * The caller owns the returned GSList but not the candidates contained within
1126 * it.
1128 * Returns: a GSList of local candidates belonging to @agent
1130 GSList *
1131 nice_agent_get_local_candidates (
1132 NiceAgent *agent,
1133 guint stream_id,
1134 guint component_id)
1135 { Component *component;
1137 if (!find_component (agent, stream_id, component_id, NULL, &component))
1138 return NULL;
1140 return g_slist_copy (component->local_candidates);
1145 * nice_agent_get_remote_candidates:
1146 * @agent: A NiceAgent
1148 * The caller owns the returned GSList but not the candidates contained within
1149 * it.
1151 * Returns: a GSList of remote candidates belonging to @agent
1153 GSList *
1154 nice_agent_get_remote_candidates (
1155 NiceAgent *agent,
1156 guint stream_id,
1157 guint component_id)
1159 Component *component;
1161 if (!find_component (agent, stream_id, component_id, NULL, &component))
1162 return NULL;
1164 return g_slist_copy (component->remote_candidates);
1168 static void
1169 nice_agent_dispose (GObject *object)
1171 GSList *i;
1172 NiceAgent *agent = NICE_AGENT (object);
1174 for (i = agent->local_addresses; i; i = i->next)
1176 NiceAddress *a = i->data;
1178 nice_address_free (a);
1181 g_slist_free (agent->local_addresses);
1182 agent->local_addresses = NULL;
1184 for (i = agent->streams; i; i = i->next)
1186 Stream *s = i->data;
1188 stream_free (s);
1191 g_slist_free (agent->streams);
1192 agent->streams = NULL;
1194 if (G_OBJECT_CLASS (nice_agent_parent_class)->dispose)
1195 G_OBJECT_CLASS (nice_agent_parent_class)->dispose (object);
1199 typedef struct _IOCtx IOCtx;
1201 struct _IOCtx
1203 NiceAgent *agent;
1204 Stream *stream;
1205 Component *component;
1206 NiceCandidate *candidate;
1210 static IOCtx *
1211 io_ctx_new (
1212 NiceAgent *agent,
1213 Stream *stream,
1214 Component *component,
1215 NiceCandidate *candidate)
1217 IOCtx *ctx;
1219 ctx = g_slice_new0 (IOCtx);
1220 ctx->agent = agent;
1221 ctx->stream = stream;
1222 ctx->component = component;
1223 ctx->candidate = candidate;
1224 return ctx;
1228 static void
1229 io_ctx_free (IOCtx *ctx)
1231 g_slice_free (IOCtx, ctx);
1235 static gboolean
1236 nice_agent_g_source_cb (
1237 GIOChannel *source,
1238 G_GNUC_UNUSED
1239 GIOCondition condition,
1240 gpointer data)
1242 /* return value is whether to keep the source */
1244 IOCtx *ctx = data;
1245 NiceAgent *agent = ctx->agent;
1246 Stream *stream = ctx->stream;
1247 Component *component = ctx->component;
1248 NiceCandidate *candidate = ctx->candidate;
1249 gchar buf[1024];
1250 guint len;
1252 len = _nice_agent_recv (agent, stream, component, candidate, 1024,
1253 buf);
1255 if (len > 0)
1256 agent->read_func (agent, candidate->stream_id, candidate->component_id,
1257 len, buf, agent->read_func_data);
1259 return TRUE;
1263 gboolean
1264 nice_agent_main_context_attach (
1265 NiceAgent *agent,
1266 GMainContext *ctx,
1267 NiceAgentRecvFunc func,
1268 gpointer data)
1270 GSList *i;
1272 if (agent->main_context_set)
1273 return FALSE;
1275 /* attach candidates */
1277 for (i = agent->streams; i; i = i->next)
1279 GSList *j;
1280 Stream *stream = i->data;
1281 Component *component = stream->component;
1283 for (j = component->local_candidates; j; j = j->next)
1285 NiceCandidate *candidate = j->data;
1286 GIOChannel *io;
1287 GSource *source;
1288 IOCtx *ctx;
1290 io = g_io_channel_unix_new (candidate->sock.fileno);
1291 source = g_io_create_watch (io, G_IO_IN);
1292 ctx = io_ctx_new (agent, stream, component, candidate);
1293 g_source_set_callback (source, (GSourceFunc) nice_agent_g_source_cb,
1294 ctx, (GDestroyNotify) io_ctx_free);
1295 g_source_attach (source, NULL);
1296 candidate->source = source;
1300 agent->main_context = ctx;
1301 agent->main_context_set = TRUE;
1302 agent->read_func = func;
1303 agent->read_func_data = data;
1304 return TRUE;