Commit a1862cc2 authored by Kai Vehmanen's avatar Kai Vehmanen

Added support for multiple components (e.g. for RTCP support). Updated to...

Added support for multiple components (e.g. for RTCP support). Updated to latest ID-17 ICE spec. Reduce the amount of debugging output.

darcs-hash:20070716095630-77cd4-d955656f1a7bb0cb8ab7b695d76aa91ee5cc7bc5.gz
parent d1ddf1e5
This diff is collapsed.
......@@ -48,7 +48,8 @@ G_BEGIN_DECLS
#define NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE 100
#define NICE_CANDIDATE_TYPE_PREF_RELAYED 60
#define NICE_CANDIDATE_MAX_FOUNDATION 16
/* Max foundation size '1*32ice-char' ICE ID-17 */
#define NICE_CANDIDATE_MAX_FOUNDATION 32+1
typedef enum
{
......
......@@ -49,12 +49,12 @@
Component *
component_new (
G_GNUC_UNUSED
ComponentType type)
guint id)
{
Component *component;
component = g_slice_new0 (Component);
component->id = 1;
component->id = id;
return component;
}
......@@ -93,6 +93,12 @@ component_free (Component *cmp)
g_slice_free (Component, cmp);
}
/**
* Returns a component UDP socket struct that uses handle 'fd'.
*
* Note: there might be multiple sockets using the same
* handle.
*/
NiceUDPSocket *
component_find_udp_socket_by_fd (Component *component, guint fd)
{
......
......@@ -46,19 +46,12 @@
G_BEGIN_DECLS
/* (ICE-13 §4.1.1) For RTP-based media streams, the RTP itself has a component
/* (ICE-16 §4.1.1.1) For RTP-based media streams, the RTP itself has a component
* ID of 1, and RTCP a component ID of 2. If an agent is using RTCP it MUST
* obtain a candidate for it. If an agent is using both RTP and RTCP, it
* would end up with 2*K host candidates if an agent has K interfaces.
*/
typedef enum
{
COMPONENT_TYPE_RTP,
COMPONENT_TYPE_RTCP,
} ComponentType;
typedef struct _Component Component;
typedef struct _CandidatePair CandidatePair;
......@@ -71,7 +64,7 @@ struct _CandidatePair
struct _Component
{
ComponentType type;
NiceComponentType type;
guint id;
NiceComponentState state;
GSList *local_candidates; /**< list of Candidate objs */
......@@ -87,7 +80,7 @@ struct _Component
Component *
component_new (
G_GNUC_UNUSED
ComponentType type);
guint component_id);
void
component_free (Component *cmp);
......
This diff is collapsed.
......@@ -166,6 +166,37 @@ static gboolean priv_add_local_candidate_pruned (Component *component, NiceCandi
return TRUE;
}
/**
* Assings a foundation to the candidate.
*
* Implements the mechanism described in ICE (ID-16) sect
* 4.1.1.4 (Computing Foundations).
*/
static void priv_assign_foundation (NiceAgent *agent, Component *component, NiceCandidate *candidate)
{
GSList *i;
for (i = component->local_candidates; i; i = i->next) {
NiceCandidate *n = i->data;
NiceAddress temp = n->base_addr;
/* note: ports are not be compared */
temp.port = candidate->base_addr.port;
if (candidate->type == n->type &&
nice_address_equal (&candidate->base_addr, &n->base_addr)) {
/* note: currently only one STUN/TURN server per stream at a
* time is supported, so there is no need to check
* for candidates that would otherwise share the
* foundation, but have different STUN/TURN servers */
memcpy (candidate->foundation, n->foundation, NICE_CANDIDATE_MAX_FOUNDATION);
return;
}
}
g_snprintf (candidate->foundation, NICE_CANDIDATE_MAX_FOUNDATION, "%u", agent->next_candidate_id++);
}
/**
* Creates a local host candidate for 'component_id' of stream
* 'stream_id'.
......@@ -191,9 +222,7 @@ NiceCandidate *discovery_add_local_host_candidate (
if (candidate) {
NiceUDPSocket *udp_socket = g_slice_new0 (NiceUDPSocket);
if (udp_socket) {
/* XXX: implement the foundation assignment as defined in
* ICE sect 4.1.1.4 ID-15: */
g_snprintf (candidate->foundation, NICE_CANDIDATE_MAX_FOUNDATION, "%u", agent->next_candidate_id++);
priv_assign_foundation (agent, component, candidate);
candidate->stream_id = stream_id;
candidate->component_id = component_id;
candidate->addr = *address;
......@@ -270,7 +299,7 @@ discovery_add_server_reflexive_candidate (
candidate->priority =
nice_candidate_ice_priority_full
(NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE, 0, component_id);
g_snprintf (candidate->foundation, NICE_CANDIDATE_MAX_FOUNDATION, "%u", agent->next_candidate_id++);
priv_assign_foundation (agent, component, candidate);
candidate->stream_id = stream_id;
candidate->component_id = component_id;
candidate->addr = *address;
......@@ -280,7 +309,10 @@ discovery_add_server_reflexive_candidate (
candidate->base_addr = base_socket->addr;
result = priv_add_local_candidate_pruned (component, candidate);
if (result != TRUE) {
if (result) {
agent_signal_new_candidate (agent, candidate);
}
else {
/* error: memory allocation, or duplicate candidatet */
nice_candidate_free (candidate), candidate = NULL;
}
......@@ -320,7 +352,7 @@ discovery_add_peer_reflexive_candidate (
(NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE, 0, component_id);
candidate->stream_id = stream_id;
candidate->component_id = component_id;
g_snprintf (candidate->foundation, NICE_CANDIDATE_MAX_FOUNDATION, "%u", agent->next_candidate_id++);
priv_assign_foundation (agent, component, candidate);
candidate->addr = *address;
candidate->base_addr = base_socket->addr;
......
......@@ -46,26 +46,107 @@
* @file stream.c
* @brief ICE stream functionality
*/
Stream *
stream_new (void)
stream_new (guint n_components)
{
Stream *stream;
guint n;
gboolean errors = FALSE;
GSList *modified_list;
Component *component;
stream = g_slice_new0 (Stream);
stream->component = component_new (COMPONENT_TYPE_RTP);
stream->n_components = 1;
for (n = 0; n < n_components; n++) {
component = component_new (n + 1);
if (component) {
modified_list = g_slist_append (stream->components, component);
if (modified_list)
stream->components = modified_list;
else
errors = TRUE;
}
else
errors = TRUE;
}
if (errors) {
stream_free (stream);
return NULL;
}
stream->n_components = n_components;
stream->initial_binding_request_received = FALSE;
return stream;
}
void
stream_free (Stream *stream)
{
component_free (stream->component);
GSList *i;
for (i = stream->components; i; i = i->next) {
Component *component = i->data;
component_free (component);
i->data = NULL;
}
g_slist_free (stream->components);
g_slice_free (Stream, stream);
}
Component *
stream_find_component_by_id (const Stream *stream, guint id)
{
GSList *i;
for (i = stream->components; i; i = i->next) {
Component *component = i->data;
if (component && component->id == id)
return component;
}
return NULL;
}
/**
* Returns true if all components of the stream are either
* 'CONNECTED' or 'READY' (connected plus nominated).
*/
gboolean
stream_all_components_ready (const Stream *stream)
{
GSList *i;
for (i = stream->components; i; i = i->next) {
Component *component = i->data;
if (component &&
(component->state == NICE_COMPONENT_STATE_CONNECTED ||
component->state == NICE_COMPONENT_STATE_READY))
return FALSE;
}
return TRUE;
}
/**
* Returns the component that owns a UDP socket using
* handle 'fd'.
*
* See also component_find_udp_socket_by_fd()
*/
Component *
stream_find_component_by_fd (const Stream *stream, guint fd)
{
GSList *i;
for (i = stream->components; i; i = i->next) {
Component *component = i->data;
NiceUDPSocket *socket =
component_find_udp_socket_by_fd (component, fd);
if (socket)
return component;
}
return NULL;
}
......@@ -59,8 +59,7 @@ struct _Stream
guint id;
guint n_components;
gboolean initial_binding_request_received;
/* XXX: streams can have multiple components */
Component *component;
GSList *components; /* list of components */
gchar local_ufrag[NICE_STREAM_MAX_UFRAG];
gchar local_password[NICE_STREAM_MAX_PWD];
gchar remote_ufrag[NICE_STREAM_MAX_UFRAG];
......@@ -68,11 +67,20 @@ struct _Stream
};
Stream *
stream_new (void);
stream_new (guint n_components);
void
stream_free (Stream *stream);
gboolean
stream_all_components_ready (const Stream *stream);
Component *
stream_find_component_by_id (const Stream *stream, guint id);
Component *
stream_find_component_by_fd (const Stream *stream, guint fd);
G_END_DECLS
#endif /* _NICE_STREAM_H */
......
......@@ -23,6 +23,7 @@
*
* Contributors:
* Dafydd Harries, Collabora Ltd.
* Kai Vehmanen, Nokia
*
* Alternatively, the contents of this file may be used under the terms of the
* the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
......@@ -62,8 +63,8 @@ main (void)
nice_agent_add_local_address (agent, &addr);
g_assert (nice_agent_add_stream (agent, 1) == 1);
g_assert (nice_agent_add_stream (agent, 1) == 2);
g_assert (nice_agent_add_stream (agent, 1) == 3);
g_assert (nice_agent_add_stream (agent, 10) == 2);
g_assert (nice_agent_add_stream (agent, 2) == 3);
g_assert (NULL != agent->streams);
......
......@@ -42,10 +42,12 @@
#include "agent.h"
#include "udp-bsd.h"
static const guint test_component_id = 1;
static NiceComponentState global_lagent_state = NICE_COMPONENT_STATE_LAST;
static NiceComponentState global_ragent_state = NICE_COMPONENT_STATE_LAST;
static guint global_components_ready = 0;
static guint global_components_ready_exit = 0;
static guint global_components_failed = 0;
static guint global_components_failed_exit = 0;
static GMainLoop *global_mainloop = NULL;
static gboolean global_lagent_gathering_done = FALSE;
static gboolean global_ragent_gathering_done = FALSE;
......@@ -104,12 +106,11 @@ static void cb_candidate_gathering_done(NiceAgent *agent, gpointer data)
(void)agent;
}
#if 0
static void cb_component_state_changed(NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data)
{
g_debug ("%s: %p", __func__, data);
g_assert (test_component_id == component_id);
if ((int)data == 1)
global_lagent_state = state;
else if ((int)data == 2)
......@@ -132,12 +133,44 @@ static void cb_component_state_changed(NiceAgent *agent, guint stream_id, guint
/* XXX: dear compiler, these are for you: */
(void)agent; (void)stream_id; (void)data;
}
#endif
static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data)
{
g_debug ("%s: %p", __func__, data);
if ((int)data == 1)
global_lagent_state = state;
else if ((int)data == 2)
global_ragent_state = state;
if (state == NICE_COMPONENT_STATE_READY)
global_components_ready++;
if (state == NICE_COMPONENT_STATE_FAILED)
global_components_failed++;
g_debug ("READY %u exit at %u.", global_components_ready, global_components_ready_exit);
/* signal status via a global variable */
if (global_components_ready == global_components_ready_exit) {
g_main_loop_quit (global_mainloop);
return;
}
/* signal status via a global variable */
if (global_components_failed == global_components_failed_exit) {
g_main_loop_quit (global_mainloop);
return;
}
/* XXX: dear compiler, these are for you: */
(void)agent; (void)stream_id; (void)data; (void)component_id;
}
static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint component_id,
gchar *lfoundation, gchar* rfoundation, gpointer data)
{
g_debug ("%s: %p", __func__, data);
g_assert (test_component_id == component_id);
if ((int)data == 1)
++global_lagent_cands;
......@@ -145,16 +178,16 @@ static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint compon
++global_ragent_cands;
/* XXX: dear compiler, these are for you: */
(void)agent; (void)stream_id;
(void)agent; (void)stream_id; (void)component_id;
}
static void cb_new_candidate(NiceAgent *agent, guint stream_id, guint component_id,
gchar *foundation, gpointer data)
{
g_debug ("%s: %p", __func__, data);
g_assert (test_component_id == component_id);
/* XXX: dear compiler, these are for you: */
(void)agent; (void)stream_id; (void)data;
(void)agent; (void)stream_id; (void)data; (void)component_id;
}
static void cb_initial_binding_request_received(NiceAgent *agent, guint stream_id, gpointer data)
......@@ -170,23 +203,40 @@ static void cb_initial_binding_request_received(NiceAgent *agent, guint stream_i
(void)agent; (void)stream_id; (void)data;
}
static void priv_get_local_addr (NiceAgent *agent, guint stream_id, guint component_id, NiceAddress *dstaddr)
{
GSList *cands, *i;
cands = nice_agent_get_local_candidates(agent, stream_id, component_id);
for (i = cands; i; i = i->next) {
NiceCandidate *cand = i->data;
if (cand) {
g_assert (dstaddr);
*dstaddr = cand->addr;
}
}
g_slist_free (cands);
}
static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr)
{
NiceAddress laddr, raddr;
NiceAddress laddr, raddr, laddr_rtcp, raddr_rtcp;
NiceCandidateDesc cdes = { /* candidate description (no ports) */
(gchar *)"1", /* foundation */
test_component_id,
0, /* component-id; filled later */
NICE_CANDIDATE_TRANSPORT_UDP, /* transport */
100000, /* priority */
NULL, /* address */
NICE_CANDIDATE_TYPE_HOST, /* type */
NULL /* base-address */
};
GSList *cands, *i;
GSList *cands;
guint ls_id, rs_id;
global_lagent_state = NICE_COMPONENT_STATE_LAST;
global_ragent_state = NICE_COMPONENT_STATE_LAST;
/* step: initialize variables modified by the callbacks */
global_components_ready = 0;
global_components_ready_exit = 4;
global_components_failed = 0;
global_components_failed_exit = 4;
global_lagent_gathering_done = FALSE;
global_ragent_gathering_done = FALSE;
global_lagent_ibr_received =
......@@ -197,9 +247,9 @@ static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *bas
g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL);
g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL);
/* step: add one stream, with one component, to each agent */
ls_id = nice_agent_add_stream (lagent, 1);
rs_id = nice_agent_add_stream (ragent, 1);
/* step: add one stream, with RTP+RTCP components, to each agent */
ls_id = nice_agent_add_stream (lagent, 2);
rs_id = nice_agent_add_stream (ragent, 2);
g_assert (ls_id > 0);
g_assert (rs_id > 0);
......@@ -214,25 +264,19 @@ static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *bas
}
/* step: find out the local candidates of each agent */
cands = nice_agent_get_local_candidates(lagent, ls_id, NICE_COMPONENT_TYPE_RTP);
for (i = cands; i; i = i->next) {
NiceCandidate *cand = i->data;
if (cand) {
g_debug ("test-fullmode: local port L %u", cand->addr.port);
laddr = cand->addr;
}
}
g_slist_free (cands);
cands = nice_agent_get_local_candidates(ragent, rs_id, NICE_COMPONENT_TYPE_RTP);
for (i = cands; i; i = i->next) {
NiceCandidate *cand = i->data;
if (cand) {
g_debug ("test-fullmode: local port R %u", cand->addr.port);
raddr = cand->addr;
}
}
g_slist_free (cands);
priv_get_local_addr (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, &raddr);
g_debug ("test-fullmode: local RTP port R %u", raddr.port);
priv_get_local_addr (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, &laddr);
g_debug ("test-fullmode: local RTP port L %u", laddr.port);
priv_get_local_addr (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, &raddr_rtcp);
g_debug ("test-fullmode: local RTCP port R %u", raddr_rtcp.port);
priv_get_local_addr (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, &laddr_rtcp);
g_debug ("test-fullmode: local RTCP port L %u", laddr_rtcp.port);
g_debug ("test-fullmode: Got local candidates...");
/* step: pass the remote candidates to agents */
......@@ -246,10 +290,17 @@ static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *bas
nice_agent_set_remote_credentials (lagent,
ls_id, ufrag, password);
}
cdes.component_id = NICE_COMPONENT_TYPE_RTP;
cdes.addr = &raddr;
nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, cands);
cdes.addr = &laddr;
nice_agent_set_remote_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, cands);
cdes.component_id = NICE_COMPONENT_TYPE_RTCP;
cdes.addr = &raddr_rtcp;
nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, cands);
cdes.addr = &laddr_rtcp;
nice_agent_set_remote_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, cands);
g_slist_free (cands);
g_debug ("test-fullmode: Set properties, next running mainloop until connectivity checks succeed...");
......@@ -263,8 +314,8 @@ static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *bas
g_assert (global_ragent_ibr_received == TRUE);
/* note: verify that correct number of local candidates were reported */
g_assert (global_lagent_cands == 1);
g_assert (global_ragent_cands == 1);
g_assert (global_lagent_cands == 2);
g_assert (global_ragent_cands == 2);
/* note: test payload send and receive */
global_ragent_read = 0;
......@@ -287,7 +338,7 @@ static int run_full_test_wrong_password (NiceAgent *lagent, NiceAgent *ragent, N
NiceAddress laddr, raddr;
NiceCandidateDesc cdes = { /* candidate description (no ports) */
(gchar *)"1", /* foundation */
test_component_id,
NICE_COMPONENT_TYPE_RTP,
NICE_CANDIDATE_TRANSPORT_UDP, /* transport */
100000, /* priority */
NULL, /* address */
......@@ -297,6 +348,10 @@ static int run_full_test_wrong_password (NiceAgent *lagent, NiceAgent *ragent, N
GSList *cands, *i;
guint ls_id, rs_id;
global_components_ready = 0;
global_components_ready_exit = 2;
global_components_failed = 0;
global_components_failed_exit = 2;
global_lagent_state =
global_ragent_state = NICE_COMPONENT_STATE_LAST;
global_lagent_gathering_done =
......@@ -387,7 +442,7 @@ static int run_full_test_control_conflict (NiceAgent *lagent, NiceAgent *ragent,
NiceAddress laddr, raddr;
NiceCandidateDesc cdes = { /* candidate description (no ports) */
(gchar *)"1", /* foundation */
test_component_id,
NICE_COMPONENT_TYPE_RTP,
NICE_CANDIDATE_TRANSPORT_UDP, /* transport */
100000, /* priority */
NULL, /* address */
......@@ -397,6 +452,10 @@ static int run_full_test_control_conflict (NiceAgent *lagent, NiceAgent *ragent,
GSList *cands, *i;
guint ls_id, rs_id;
global_components_ready = 0;
global_components_ready_exit = 2;
global_components_failed = 0;
global_components_failed_exit = 2;
global_lagent_state =
global_ragent_state = NICE_COMPONENT_STATE_LAST;
global_lagent_gathering_done =
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment