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
...@@ -127,9 +127,6 @@ agent_find_component ( ...@@ -127,9 +127,6 @@ agent_find_component (
{ {
Stream *s; Stream *s;
if (component_id != 1)
return FALSE;
s = agent_find_stream (agent, stream_id); s = agent_find_stream (agent, stream_id);
if (s == NULL) if (s == NULL)
...@@ -139,7 +136,7 @@ agent_find_component ( ...@@ -139,7 +136,7 @@ agent_find_component (
*stream = s; *stream = s;
if (component) if (component)
*component = s->component; *component = stream_find_component_by_id (s, component_id);
return TRUE; return TRUE;
} }
...@@ -548,6 +545,44 @@ static void priv_signal_component_state_connecting (NiceAgent *agent, guint stre ...@@ -548,6 +545,44 @@ static void priv_signal_component_state_connecting (NiceAgent *agent, guint stre
} }
#endif #endif
static gboolean
priv_add_srv_rfx_candidate_discovery (NiceAgent *agent, NiceCandidate *host_candidate, const gchar *stun_server_ip, const guint stun_server_port, Stream *stream, guint component_id, NiceAddress *addr)
{
CandidateDiscovery *cdisco;
GSList *modified_list;
/* note: no need to check for redundant candidates, as this is
* done later on in the process */
cdisco = g_slice_new0 (CandidateDiscovery);
if (cdisco) {
modified_list = g_slist_append (agent->discovery_list, cdisco);
if (modified_list) {
agent->discovery_list = modified_list;
cdisco->type = NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE;
cdisco->socket = host_candidate->sockptr->fileno;
cdisco->nicesock = host_candidate->sockptr;
cdisco->server_addr = stun_server_ip;
cdisco->server_port = stun_server_port;
cdisco->interface = addr;
cdisco->stream = stream;
cdisco->component = stream_find_component_by_id (stream, component_id);
cdisco->agent = agent;
g_debug ("Adding new srv-rflx candidate discovery %p\n", cdisco);
modified_list = g_slist_append (agent->discovery_list, cdisco);
if (modified_list) {
agent->discovery_list = modified_list;
++agent->discovery_unsched_items;
}
}
return TRUE;
}
return FALSE;
}
/** /**
* nice_agent_add_stream: * nice_agent_add_stream:
* @agent: a NiceAgent * @agent: a NiceAgent
...@@ -566,13 +601,12 @@ nice_agent_add_stream ( ...@@ -566,13 +601,12 @@ nice_agent_add_stream (
{ {
Stream *stream; Stream *stream;
GSList *i, *modified_list = NULL; GSList *i, *modified_list = NULL;
guint n;
g_assert (n_components == 1);
if (!agent->local_addresses) if (!agent->local_addresses)
return 0; return 0;
stream = stream_new (); stream = stream_new (n_components);
if (stream) { if (stream) {
modified_list = g_slist_append (agent->streams, stream); modified_list = g_slist_append (agent->streams, stream);
if (modified_list) { if (modified_list) {
...@@ -600,56 +634,39 @@ nice_agent_add_stream ( ...@@ -600,56 +634,39 @@ nice_agent_add_stream (
for (i = agent->local_addresses; i; i = i->next) for (i = agent->local_addresses; i; i = i->next)
{ {
NiceAddress *addr = i->data; NiceAddress *addr = i->data;
CandidateDiscovery *cand;
NiceCandidate *host_candidate; NiceCandidate *host_candidate;
/* XXX: not multi-component ready */ for (n = 0; n < n_components; n++) {
host_candidate = discovery_add_local_host_candidate (agent, stream->id, host_candidate = discovery_add_local_host_candidate (agent, stream->id,
stream->component->id, addr); n + 1, addr);
if (!host_candidate) { if (!host_candidate) {
stream->id = 0; stream->id = 0;
break; break;
} }
if (agent->full_mode &&
agent->stun_server_ip) {
/* note: no need to check for redundant candidates, as this is if (agent->full_mode &&
* done later on in the process */ agent->stun_server_ip) {
cand = g_slice_new0 (CandidateDiscovery); gboolean res =
if (cand) { priv_add_srv_rfx_candidate_discovery (agent,
modified_list = g_slist_append (agent->discovery_list, cand); host_candidate,
agent->stun_server_ip,
if (modified_list) { agent->stun_server_port,
agent->discovery_list = modified_list; stream,
cand->type = NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE; n + 1 /* component-id */,
cand->socket = host_candidate->sockptr->fileno; addr);
cand->nicesock = host_candidate->sockptr;
cand->server_addr = agent->stun_server_ip; if (res != TRUE) {
cand->server_port = agent->stun_server_port; /* note: memory allocation failure, return error */
cand->interface = addr; stream->id = 0;
cand->stream = stream; break;
/* XXX: not multi-component ready */
cand->component = stream->component;
cand->agent = agent;
g_debug ("Adding new srv-rflx candidate %p\n", cand);
modified_list = g_slist_append (agent->discovery_list, cand);
if (modified_list) {
agent->discovery_list = modified_list;
++agent->discovery_unsched_items;
}
} }
} }
else {
/* note: memory allocation failure, return error */
stream->id = 0;
break;
}
} }
} }
/* step: attach the newly created sockets to the mainloop /* step: attach the newly created sockets to the mainloop
* context */ * context */
if (agent->main_context_set && stream->id > 0) if (agent->main_context_set && stream->id > 0)
...@@ -1102,7 +1119,7 @@ nice_agent_recv ( ...@@ -1102,7 +1119,7 @@ nice_agent_recv (
socket = component_find_udp_socket_by_fd (component, j); socket = component_find_udp_socket_by_fd (component, j);
g_assert (socket); g_assert (socket);
len = _nice_agent_recv (agent, stream, component, socket, len = _nice_agent_recv (agent, stream, component, socket,
buf_len, buf); buf_len, buf);
...@@ -1136,8 +1153,7 @@ nice_agent_recv_sock ( ...@@ -1136,8 +1153,7 @@ nice_agent_recv_sock (
socket = component_find_udp_socket_by_fd (component, sock); socket = component_find_udp_socket_by_fd (component, sock);
g_assert (socket); g_assert (socket);
/* XXX: not multi-component ready */ return _nice_agent_recv (agent, stream, component,
return _nice_agent_recv (agent, stream, stream->component,
socket, buf_len, buf); socket, buf_len, buf);
} }
...@@ -1172,18 +1188,21 @@ nice_agent_poll_read ( ...@@ -1172,18 +1188,21 @@ nice_agent_poll_read (
for (i = agent->streams; i; i = i->next) for (i = agent->streams; i; i = i->next)
{ {
GSList *j; GSList *j, *k;
Stream *stream = i->data; Stream *stream = i->data;
/* XXX: not multi-component ready */
Component *component = stream->component;
for (j = component->sockets; j; j = j->next) for (k = stream->components; k; k = k->next)
{ {
NiceUDPSocket *sockptr = j->data; Component *component = k->data;
FD_SET (sockptr->fileno, &fds); for (j = component->sockets; j; j = j->next)
max_fd = MAX (sockptr->fileno, max_fd); {
} NiceUDPSocket *sockptr = j->data;
FD_SET (sockptr->fileno, &fds);
max_fd = MAX (sockptr->fileno, max_fd);
}
}
} }
for (i = other_fds; i; i = i->next) for (i = other_fds; i; i = i->next)
...@@ -1216,31 +1235,32 @@ nice_agent_poll_read ( ...@@ -1216,31 +1235,32 @@ nice_agent_poll_read (
{ {
NiceUDPSocket *socket = NULL; NiceUDPSocket *socket = NULL;
Stream *stream = NULL; Stream *stream = NULL;
Component *component = NULL;
gchar buf[MAX_STUN_DATAGRAM_PAYLOAD]; gchar buf[MAX_STUN_DATAGRAM_PAYLOAD];
guint len; guint len;
for (i = agent->streams; i; i = i->next) for (i = agent->streams; i; i = i->next)
{ {
Stream *s = i->data; Stream *s = i->data;
Component *c = s->component; Component *c = stream_find_component_by_fd (s, j);
socket = component_find_udp_socket_by_fd (c, j); socket = component_find_udp_socket_by_fd (c, j);
if (socket != NULL) { if (socket != NULL) {
stream = s; stream = s;
component = c;
break; break;
} }
} }
if (socket == NULL || stream == NULL) if (socket == NULL || stream == NULL || component == NULL)
break; break;
/* XXX: not multi-component ready */ len = _nice_agent_recv (agent, stream, component,
len = _nice_agent_recv (agent, stream, stream->component,
socket, MAX_STUN_DATAGRAM_PAYLOAD, buf); socket, MAX_STUN_DATAGRAM_PAYLOAD, buf);
if (len && func != NULL) if (len && func != NULL)
func (agent, stream->id, stream->component->id, len, buf, func (agent, stream->id, component->id, len, buf,
data); data);
} }
} }
...@@ -1268,13 +1288,7 @@ nice_agent_send ( ...@@ -1268,13 +1288,7 @@ nice_agent_send (
Stream *stream; Stream *stream;
Component *component; Component *component;
/* note: dear compiler, these are for you: */ agent_find_component (agent, stream_id, component_id, &stream, &component);
(void)component_id;
stream = agent_find_stream (agent, stream_id);
/* XXX: not multi-component ready */
component = stream->component;
if (component->selected_pair.local != NULL) if (component->selected_pair.local != NULL)
{ {
...@@ -1475,30 +1489,32 @@ nice_agent_g_source_cb ( ...@@ -1475,30 +1489,32 @@ nice_agent_g_source_cb (
*/ */
static gboolean priv_attach_new_stream (NiceAgent *agent, Stream *stream) static gboolean priv_attach_new_stream (NiceAgent *agent, Stream *stream)
{ {
GSList *j; GSList *i, *j;
/* XXX: not multi-component ready */
Component *component = stream->component; for (i = stream->components; i; i = i->next) {
Component *component = i->data;
for (j = component->sockets; j; j = j->next) {
NiceUDPSocket *udp_socket = j->data; for (j = component->sockets; j; j = j->next) {
GIOChannel *io; NiceUDPSocket *udp_socket = j->data;
GSource *source; GIOChannel *io;
IOCtx *ctx; GSource *source;
GSList *modified_list; IOCtx *ctx;
GSList *modified_list;
io = g_io_channel_unix_new (udp_socket->fileno); io = g_io_channel_unix_new (udp_socket->fileno);
source = g_io_create_watch (io, G_IO_IN); source = g_io_create_watch (io, G_IO_IN);
ctx = io_ctx_new (agent, stream, component, udp_socket); ctx = io_ctx_new (agent, stream, component, udp_socket);
g_source_set_callback (source, (GSourceFunc) nice_agent_g_source_cb, g_source_set_callback (source, (GSourceFunc) nice_agent_g_source_cb,
ctx, (GDestroyNotify) io_ctx_free); ctx, (GDestroyNotify) io_ctx_free);
g_debug ("Attach source %p (stream %u).", source, stream->id); g_debug ("Attach source %p (stream %u).", source, stream->id);
g_source_attach (source, NULL); g_source_attach (source, NULL);
modified_list = g_slist_append (component->gsources, source); modified_list = g_slist_append (component->gsources, source);
if (!modified_list) { if (!modified_list) {
g_source_destroy (source); g_source_destroy (source);
return FALSE; return FALSE;
}
component->gsources = modified_list;
} }
component->gsources = modified_list;
} }
return TRUE; return TRUE;
...@@ -1512,18 +1528,20 @@ static gboolean priv_attach_new_stream (NiceAgent *agent, Stream *stream) ...@@ -1512,18 +1528,20 @@ static gboolean priv_attach_new_stream (NiceAgent *agent, Stream *stream)
*/ */
static void priv_deattach_stream (Stream *stream) static void priv_deattach_stream (Stream *stream)
{ {
GSList *j; GSList *i, *j;
/* XXX: not multi-component ready */
Component *component = stream->component; for (i = stream->components; i; i = i->next) {
Component *component = i->data;
for (j = component->gsources; j; j = j->next) {
GSource *source = j->data; for (j = component->gsources; j; j = j->next) {
g_debug ("Detach source %p (stream %u).", source, stream->id); GSource *source = j->data;
g_source_destroy (source); g_debug ("Detach source %p (stream %u).", source, stream->id);
} g_source_destroy (source);
}
g_slist_free (component->gsources), g_slist_free (component->gsources),
component->gsources = NULL; component->gsources = NULL;
}
} }
NICEAPI_EXPORT gboolean NICEAPI_EXPORT gboolean
......
...@@ -48,7 +48,8 @@ G_BEGIN_DECLS ...@@ -48,7 +48,8 @@ G_BEGIN_DECLS
#define NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE 100 #define NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE 100
#define NICE_CANDIDATE_TYPE_PREF_RELAYED 60 #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 typedef enum
{ {
......
...@@ -49,12 +49,12 @@ ...@@ -49,12 +49,12 @@
Component * Component *
component_new ( component_new (
G_GNUC_UNUSED G_GNUC_UNUSED
ComponentType type) guint id)
{ {
Component *component; Component *component;
component = g_slice_new0 (Component); component = g_slice_new0 (Component);
component->id = 1; component->id = id;
return component; return component;
} }
...@@ -93,6 +93,12 @@ component_free (Component *cmp) ...@@ -93,6 +93,12 @@ component_free (Component *cmp)
g_slice_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 * NiceUDPSocket *
component_find_udp_socket_by_fd (Component *component, guint fd) component_find_udp_socket_by_fd (Component *component, guint fd)
{ {
......
...@@ -46,19 +46,12 @@ ...@@ -46,19 +46,12 @@
G_BEGIN_DECLS 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 * 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 * 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. * 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 _Component Component;
typedef struct _CandidatePair CandidatePair; typedef struct _CandidatePair CandidatePair;
...@@ -71,7 +64,7 @@ struct _CandidatePair ...@@ -71,7 +64,7 @@ struct _CandidatePair
struct _Component struct _Component
{ {
ComponentType type; NiceComponentType type;
guint id; guint id;
NiceComponentState state; NiceComponentState state;
GSList *local_candidates; /**< list of Candidate objs */ GSList *local_candidates; /**< list of Candidate objs */
...@@ -87,7 +80,7 @@ struct _Component ...@@ -87,7 +80,7 @@ struct _Component
Component * Component *
component_new ( component_new (
G_GNUC_UNUSED G_GNUC_UNUSED
ComponentType type); guint component_id);
void void
component_free (Component *cmp); component_free (Component *cmp);
......
...@@ -91,6 +91,10 @@ static CandidateCheckPair *priv_conn_check_find_next_waiting (GSList *conn_check ...@@ -91,6 +91,10 @@ static CandidateCheckPair *priv_conn_check_find_next_waiting (GSList *conn_check
*/ */
static gboolean priv_conn_check_initiate (NiceAgent *agent, CandidateCheckPair *pair) static gboolean priv_conn_check_initiate (NiceAgent *agent, CandidateCheckPair *pair)
{ {
/* XXX: from ID-16 onwards, the checks should not be sent
* immediately, but be put into the "triggered queue",
* see "7.2.1.4 Triggered Checks"
*/
g_get_current_time (&pair->next_tick); g_get_current_time (&pair->next_tick);
g_time_val_add (&pair->next_tick, agent->timer_ta * 10); g_time_val_add (&pair->next_tick, agent->timer_ta * 10);
pair->state = NICE_CHECK_IN_PROGRESS; pair->state = NICE_CHECK_IN_PROGRESS;
...@@ -100,33 +104,57 @@ static gboolean priv_conn_check_initiate (NiceAgent *agent, CandidateCheckPair * ...@@ -100,33 +104,57 @@ static gboolean priv_conn_check_initiate (NiceAgent *agent, CandidateCheckPair *
/** /**
* Unfreezes the next connectivity check in the list. Follows the * Unfreezes the next connectivity check in the list. Follows the
* algorithm defined in 5.7.4 of the ICE spec (-15). * algorithm (2.) defined in 5.7.4 (Computing States) of the ICE spec
* (ID-17), with some exceptions (see comments in code).
*
* See also sect 7.1.2.2.3 (Updating Pair States), and
* priv_conn_check_unfreeze_related().
* *
* @return TRUE on success, and FALSE if no frozen candidates were found. * @return TRUE on success, and FALSE if no frozen candidates were found.
*/ */
static gboolean priv_conn_check_unfreeze_next (GSList *conncheck_list) static gboolean priv_conn_check_unfreeze_next (NiceAgent *agent, GSList *conncheck_list)
{ {
CandidateCheckPair *pair = NULL; CandidateCheckPair *pair = NULL;
guint64 max_priority = 0; guint64 max_frozen_priority = 0;
GSList *i; GSList *i;
int c; guint c;
guint max_components = 0;
gboolean frozen = FALSE;
/* step: calculate the max number of components across streams */
for (i = agent->streams; i; i = i->next) {
Stream *stream = i->data;
if (stream->n_components > max_components)
max_components = stream->n_components;
}
/* note: the pair list is already sorted so separate prio check /* note: the pair list is already sorted so separate prio check
* is not needed */ * is not needed */
for (c = NICE_COMPONENT_TYPE_RTP; (pair == NULL) && c < NICE_COMPONENT_TYPE_RTCP; c++) { /* XXX: the unfreezing is implemented a bit differently than in the
* current ICE spec, but should still be interoperate:
* - checks are not grouped by foundation
* - one frozen check is unfrozen (lowest component-id, highest
* priority)
*/
for (c = 0; (pair == NULL) && c < max_components; c++) {
for (i = conncheck_list; i ; i = i->next) { for (i = conncheck_list; i ; i = i->next) {
CandidateCheckPair *p = i->data; CandidateCheckPair *p = i->data;
if (p->state == NICE_CHECK_FROZEN && if (p->component_id == c + 1) {
p->priority > max_priority) { if (p->state == NICE_CHECK_FROZEN) {
max_priority = p->priority; frozen = TRUE;
pair = p; if (p->priority > max_frozen_priority) {
max_frozen_priority = p->priority;
pair = p;
}
}
} }
} }
} }
if (pair) { if (pair) {
g_debug ("Pair %p (%s) unfrozen.", pair, pair->foundation); g_debug ("Pair %p with s/c-id %u/%u (%s) unfrozen.", pair, pair->stream_id, pair->component_id, pair->foundation);
pair->state = NICE_CHECK_WAITING; pair->state = NICE_CHECK_WAITING;
return TRUE; return TRUE;
} }
...@@ -134,6 +162,69 @@ static gboolean priv_conn_check_unfreeze_next (GSList *conncheck_list) ...@@ -134,6 +162,69 @@ static gboolean priv_conn_check_unfreeze_next (GSList *conncheck_list)
return FALSE; return FALSE;
} }
/**
* Unfreezes the next next connectivity check in the list after
* check 'success_check' has succesfully completed.
*
* See sect 7.1.2.2.3 (Updating Pair States) of ICE spec (ID-17).
*
* @param agent context
* @param ok_check a connectivity check that has just completed
*
* @return TRUE on success, and FALSE if no frozen candidates were found.
*/
static void priv_conn_check_unfreeze_related (NiceAgent *agent, CandidateCheckPair *ok_check)
{
GSList *i, *j;
Stream *stream;
guint unfrozen = 0;
g_assert (ok_check);
g_assert (ok_check->state == NICE_CHECK_SUCCEEDED);
/* step: perform the step (1) of 'Updating Pair States' */
for (i = agent->conncheck_list; i ; i = i->next) {
CandidateCheckPair *p = i->data;
if (p->stream_id == ok_check->stream_id) {
if (p->state == NICE_CHECK_FROZEN &&
strcmp (p->foundation, ok_check->foundation) == 0) {
g_debug ("Unfreezing check %p (related to %p).", p, ok_check);
p->state = NICE_CHECK_WAITING;
}
}
}
/* step: perform the step (2) of 'Updating Pair States' */
stream = agent_find_stream (agent, ok_check->stream_id);
if (stream_all_components_ready (stream)) {
/* step: unfreeze checks from other streams */
for (i = agent->streams; i ; i = i->next) {
Stream *s = i->data;
for (j = agent->conncheck_list; j ; j = j->next) {
CandidateCheckPair *p = j->data;
if (p->stream_id == s->id &&
p->stream_id != ok_check->stream_id) {
if (p->state == NICE_CHECK_FROZEN &&
strcmp (p->foundation, ok_check->foundation) == 0) {
g_debug ("Unfreezing check %p from stream %u (related to %p).", p, s->id, ok_check);
p->state = NICE_CHECK_WAITING;
++unfrozen;
}
}
}
/* note: only unfreeze check from one stream at a time */
if (unfrozen)
break;
}
}
if (unfrozen == 0)
priv_conn_check_unfreeze_next (agent, agent->conncheck_list);
}
/** /**
* Timer callback that handles initiating and managing connectivity * Timer callback that handles initiating and managing connectivity
* checks (paced by the Ta timer). * checks (paced by the Ta timer).
...@@ -161,13 +252,6 @@ static gboolean priv_conn_check_tick (gpointer pointer) ...@@ -161,13 +252,6 @@ static gboolean priv_conn_check_tick (gpointer pointer)
} }
#endif #endif
if (!pair) {
gboolean c = priv_conn_check_unfreeze_next (agent->conncheck_list);
if (c == TRUE) {
pair = priv_conn_check_find_next_waiting (agent->conncheck_list);
}
}
if (pair) { if (pair) {
priv_conn_check_initiate (agent, pair); priv_conn_check_initiate (agent, pair);
keep_timer_going = TRUE; keep_timer_going = TRUE;
...@@ -233,6 +317,10 @@ static gboolean priv_conn_check_tick (gpointer pointer) ...@@ -233,6 +317,10 @@ static gboolean priv_conn_check_tick (gpointer pointer)
(succeeded && nominated == 0)) (succeeded && nominated == 0))
keep_timer_going = TRUE; keep_timer_going = TRUE;
/* note: if no waiting checks, unfreeze one check */
if (!waiting && frozen)
priv_conn_check_unfreeze_next (agent, agent->conncheck_list);
/* step: nominate some candidate /* step: nominate some candidate
* - no work left but still no nominated checks (possibly * - no work left but still no nominated checks (possibly
* caused by a controlling-controlling role conflict) * caused by a controlling-controlling role conflict)
...@@ -280,7 +368,7 @@ static gboolean priv_conn_check_tick (gpointer pointer) ...@@ -280,7 +368,7 @@ static gboolean priv_conn_check_tick (gpointer pointer)
static gboolean priv_conn_keepalive_tick (gpointer pointer) static gboolean priv_conn_keepalive_tick (gpointer pointer)
{ {
NiceAgent *agent = pointer; NiceAgent *agent = pointer;
GSList *i; GSList *i, *j;
int errors = 0; int errors = 0;
g_debug ("%s", G_STRFUNC); g_debug ("%s", G_STRFUNC);
...@@ -288,27 +376,29 @@ static gboolean priv_conn_keepalive_tick (gpointer pointer) ...@@ -288,27 +376,29 @@ static gboolean priv_conn_keepalive_tick (gpointer pointer)
/* case 1: session established and media flowing /* case 1: session established and media flowing
* (ref ICE sect 10 ID-16) */ * (ref ICE sect 10 ID-16) */
for (i = agent->streams; i; i = i->next) { for (i = agent->streams; i; i = i->next) {
/* XXX: not multi-component ready */
Stream *stream = i->data; Stream *stream = i->data;
Component *component = stream->component; for (j = stream->components; j; j = j->next) {
if (component->selected_pair.local != NULL && Component *component = j->data;
component->media_after_tick != TRUE) { if (component->selected_pair.local != NULL &&
CandidatePair *p = &component->selected_pair; component->media_after_tick != TRUE) {
struct sockaddr sockaddr; CandidatePair *p = &component->selected_pair;
int res; struct sockaddr sockaddr;
int res;
memset (&sockaddr, 0, sizeof (sockaddr));
nice_address_copy_to_sockaddr (&p->remote->addr, &sockaddr); memset (&sockaddr, 0, sizeof (sockaddr));
nice_address_copy_to_sockaddr (&p->remote->addr, &sockaddr);
res = stun_bind_keepalive (p->local->sockptr->fileno,
&sockaddr, sizeof (sockaddr)); res = stun_bind_keepalive (p->local->sockptr->fileno,
g_debug ("stun_bind_keepalive for pair %p res %d.", p, res); &sockaddr, sizeof (sockaddr));
if (res < 0) g_debug ("stun_bind_keepalive for pair %p res %d.", p, res);
++errors; if (res < 0)
++errors;
}
component->media_after_tick = FALSE;
} }
component->media_after_tick = FALSE;
} }
/* case 2: connectivity establishment ongoing /* case 2: connectivity establishment ongoing
* (ref ICE sect 4.1.1.5 ID-15) */ * (ref ICE sect 4.1.1.5 ID-15) */
if (agent->conncheck_state == NICE_CHECKLIST_RUNNING) { if (agent->conncheck_state == NICE_CHECKLIST_RUNNING) {
...@@ -336,7 +426,7 @@ static gboolean priv_conn_keepalive_tick (gpointer pointer) ...@@ -336,7 +426,7 @@ static gboolean priv_conn_keepalive_tick (gpointer pointer)
*/ */
void conn_check_schedule_next (NiceAgent *agent) void conn_check_schedule_next (NiceAgent *agent)
{ {
gboolean c = priv_conn_check_unfreeze_next (agent->conncheck_list); gboolean c = priv_conn_check_unfreeze_next (agent, agent->conncheck_list);
if (agent->discovery_unsched_items > 0) if (agent->discovery_unsched_items > 0)
g_debug ("WARN: starting conn checks before local candidate gathering is finished."); g_debug ("WARN: starting conn checks before local candidate gathering is finished.");
...@@ -621,11 +711,11 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair) ...@@ -621,11 +711,11 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
{ {
gchar tmpbuf[INET6_ADDRSTRLEN]; gchar tmpbuf[INET6_ADDRSTRLEN];
nice_address_to_string (&pair->remote->addr, tmpbuf); nice_address_to_string (&pair->remote->addr, tmpbuf);
g_debug ("STUN-CC REQ to '%s:%u', socket=%u, pair=%s, tie=%llu, username='%s', password='%s', priority=%u.", g_debug ("STUN-CC REQ to '%s:%u', socket=%u, pair=%s (c-id:%u), tie=%llu, username='%s', password='%s', priority=%u.",
tmpbuf, tmpbuf,
ntohs(((struct sockaddr_in*)(&sockaddr))->sin_port), ntohs(((struct sockaddr_in*)(&sockaddr))->sin_port),
pair->local->sockptr->fileno, pair->local->sockptr->fileno,
pair->foundation, pair->foundation, pair->component_id,
(unsigned long long)agent->tie_breaker, (unsigned long long)agent->tie_breaker,
agent->ufragtmp, password, priority); agent->ufragtmp, password, priority);
...@@ -667,10 +757,14 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair) ...@@ -667,10 +757,14 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
static void priv_update_check_list_state (NiceAgent *agent, Stream *stream) static void priv_update_check_list_state (NiceAgent *agent, Stream *stream)
{ {
GSList *i; GSList *i;
guint c; /* note: emitting a signal might cause the client
* to remove the stream, thus the component count
* must be fetched before entering the loop*/
guint c, components = stream->n_components;
/* note: iterate the conncheck list for each component separately */ /* note: iterate the conncheck list for each component separately */
for (c = 0; c < stream->n_components; c++) { for (c = 0; c < components; c++) {
guint not_failed = 0, checks = 0; guint not_failed = 0, checks = 0;
for (i = agent->conncheck_list; i; i = i->next) { for (i = agent->conncheck_list; i; i = i->next) {
CandidateCheckPair *p = i->data; CandidateCheckPair *p = i->data;
...@@ -695,7 +789,35 @@ static void priv_update_check_list_state (NiceAgent *agent, Stream *stream) ...@@ -695,7 +789,35 @@ static void priv_update_check_list_state (NiceAgent *agent, Stream *stream)
stream->id, stream->id,
(c + 1), /* component-id */ (c + 1), /* component-id */
NICE_COMPONENT_STATE_FAILED); NICE_COMPONENT_STATE_FAILED);
}
}
/**
* Implemented the pruning steps described in ICE sect 8.1.2 (ID-16)
* after a pair has been nominated.
*
* @see priv_update_check_list_state_for_component()
*/
static void priv_prune_pending_checks (NiceAgent *agent, guint component_id)
{
GSList *i;
/* step: cancel all FROZEN and WAITING pairs for the component */
for (i = agent->conncheck_list; i; i = i->next) {
CandidateCheckPair *p = i->data;
if (p->component_id == component_id) {
if (p->state == NICE_CHECK_FROZEN ||
p->state == NICE_CHECK_WAITING)
p->state = NICE_CHECK_CANCELLED;
/* note: a SHOULD level req. in ICE ID-15: */
if (p->state == NICE_CHECK_IN_PROGRESS) {
if (p->stun_ctx)
stun_bind_cancel (p->stun_ctx),
p->stun_ctx = NULL;
p->state = NICE_CHECK_CANCELLED;
}
}
} }
} }
...@@ -710,7 +832,7 @@ static void priv_update_check_list_state (NiceAgent *agent, Stream *stream) ...@@ -710,7 +832,7 @@ static void priv_update_check_list_state (NiceAgent *agent, Stream *stream)
static void priv_update_check_list_state_for_component (NiceAgent *agent, Stream *stream, Component *component) static void priv_update_check_list_state_for_component (NiceAgent *agent, Stream *stream, Component *component)
{ {
GSList *i; GSList *i;
unsigned int succeeded = 0, nominated = 0; guint succeeded = 0, nominated = 0;
g_assert (component); g_assert (component);
...@@ -722,7 +844,7 @@ static void priv_update_check_list_state_for_component (NiceAgent *agent, Stream ...@@ -722,7 +844,7 @@ static void priv_update_check_list_state_for_component (NiceAgent *agent, Stream
p->state == NICE_CHECK_DISCOVERED) { p->state == NICE_CHECK_DISCOVERED) {
++succeeded; ++succeeded;
if (p->nominated == TRUE) { if (p->nominated == TRUE) {
++nominated; priv_prune_pending_checks (agent, p->component_id);
agent_signal_component_state_change (agent, agent_signal_component_state_change (agent,
p->stream_id, p->stream_id,
p->component_id, p->component_id,
...@@ -734,24 +856,6 @@ static void priv_update_check_list_state_for_component (NiceAgent *agent, Stream ...@@ -734,24 +856,6 @@ static void priv_update_check_list_state_for_component (NiceAgent *agent, Stream
g_debug ("conn.check list status: %u nominated, %u succeeded, c-id %u.", nominated, succeeded, component->id); g_debug ("conn.check list status: %u nominated, %u succeeded, c-id %u.", nominated, succeeded, component->id);
if (nominated) {
/* step: cancel all FROZEN and WAITING pairs for the component */
for (i = agent->conncheck_list; i; i = i->next) {
CandidateCheckPair *p = i->data;
if (p->state == NICE_CHECK_FROZEN ||
p->state == NICE_CHECK_WAITING)
p->state = NICE_CHECK_CANCELLED;
/* note: a SHOULD level req. in ICE ID-15: */
if (p->state == NICE_CHECK_IN_PROGRESS) {
if (p->stun_ctx)
stun_bind_cancel (p->stun_ctx),
p->stun_ctx = NULL;
p->state = NICE_CHECK_CANCELLED;
}
}
}
priv_update_check_list_state (agent, stream); priv_update_check_list_state (agent, stream);
} }
...@@ -888,12 +992,12 @@ static void priv_reply_to_conn_check (NiceAgent *agent, Stream *stream, Componen ...@@ -888,12 +992,12 @@ static void priv_reply_to_conn_check (NiceAgent *agent, Stream *stream, Componen
{ {
gchar tmpbuf[INET6_ADDRSTRLEN]; gchar tmpbuf[INET6_ADDRSTRLEN];
nice_address_to_string (&cand->addr, tmpbuf); nice_address_to_string (&cand->addr, tmpbuf);
g_debug ("STUN-CC RESP to '%s:%u', socket=%u, len=%u, cand=%p, use-cand=%d.", g_debug ("STUN-CC RESP to '%s:%u', socket=%u, len=%u, cand=%p (c-id:%u), use-cand=%d.",
tmpbuf, tmpbuf,
cand->addr.port, cand->addr.port,
udp_socket->fileno, udp_socket->fileno,
rbuf_len, rbuf_len,
cand, cand, component->id,
(int)use_candidate); (int)use_candidate);
} }
#endif #endif
...@@ -993,6 +1097,7 @@ static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, Stream * ...@@ -993,6 +1097,7 @@ static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, Stream *
text */ text */
p->state = NICE_CHECK_SUCCEEDED; p->state = NICE_CHECK_SUCCEEDED;
g_debug ("conncheck %p SUCCEEDED.", p); g_debug ("conncheck %p SUCCEEDED.", p);
priv_conn_check_unfreeze_related (agent, p);
} }
else { else {
NiceCandidate *cand = NiceCandidate *cand =
...@@ -1070,34 +1175,37 @@ static gboolean priv_map_reply_to_discovery_request (NiceAgent *agent, gchar *bu ...@@ -1070,34 +1175,37 @@ static gboolean priv_map_reply_to_discovery_request (NiceAgent *agent, gchar *bu
for (i = agent->discovery_list; i && trans_found != TRUE; i = i->next) { for (i = agent->discovery_list; i && trans_found != TRUE; i = i->next) {
CandidateDiscovery *d = i->data; CandidateDiscovery *d = i->data;
res = stun_bind_process (d->stun_ctx, buf, len, &sockaddr, &socklen); if (d->stun_ctx) {
g_debug ("stun_bind_process/disc for %p res %d.", d, res); res = stun_bind_process (d->stun_ctx, buf, len, &sockaddr, &socklen);
if (res == 0) { g_debug ("stun_bind_process/disc for %p res %d.", d, res);
/* case: succesful binding discovery, create a new local candidate */ if (res == 0) {
NiceAddress niceaddr; /* case: succesful binding discovery, create a new local candidate */
struct sockaddr_in *mapped = (struct sockaddr_in *)&sockaddr; NiceAddress niceaddr;
niceaddr.type = NICE_ADDRESS_TYPE_IPV4; struct sockaddr_in *mapped = (struct sockaddr_in *)&sockaddr;
niceaddr.addr.addr_ipv4 = ntohl(mapped->sin_addr.s_addr); niceaddr.type = NICE_ADDRESS_TYPE_IPV4;
niceaddr.port = ntohs(mapped->sin_port); niceaddr.addr.addr_ipv4 = ntohl(mapped->sin_addr.s_addr);
discovery_add_server_reflexive_candidate ( niceaddr.port = ntohs(mapped->sin_port);
d->agent,
d->stream->id, discovery_add_server_reflexive_candidate (
d->component->id, d->agent,
&niceaddr, d->stream->id,
d->nicesock); d->component->id,
&niceaddr,
d->stun_ctx = NULL; d->nicesock);
d->done = TRUE;
trans_found = TRUE; d->stun_ctx = NULL;
} d->done = TRUE;
else if (res != EAGAIN) { trans_found = TRUE;
/* case: STUN error, the check STUN context was freed */ }
d->stun_ctx = NULL; else if (res != EAGAIN) {
d->done = TRUE; /* case: STUN error, the check STUN context was freed */
trans_found = TRUE; d->stun_ctx = NULL;
} d->done = TRUE;
else { trans_found = TRUE;
g_assert (res == EAGAIN); }
else {
g_assert (res == EAGAIN);
}
} }
} }
...@@ -1164,7 +1272,9 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream, Compo ...@@ -1164,7 +1272,9 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream, Compo
nice_address_copy_to_sockaddr (from, &sockaddr); nice_address_copy_to_sockaddr (from, &sockaddr);
/* note: contents of 'buf' already validated, so it is /* note: contents of 'buf' already validated, so it is
* a valid and full received STUN message */ * a valid and fully received STUN message */
g_debug ("inbound STUN packet for stream/component %u/%u:", stream->id, component->id);
/* note: ICE ID-16, 7.2 */ /* note: ICE ID-16, 7.2 */
...@@ -1250,6 +1360,9 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream, Compo ...@@ -1250,6 +1360,9 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, Stream *stream, Compo
if (trans_found != TRUE) if (trans_found != TRUE)
trans_found = trans_found =
priv_map_reply_to_discovery_request (agent, buf, len); priv_map_reply_to_discovery_request (agent, buf, len);
if (trans_found != TRUE)
g_debug ("Unable to match to an existing transaction, probably a keepalive.");
} }
else { else {
g_debug ("Invalid STUN connectivity check request. Ignoring... %s", strerror(errno)); g_debug ("Invalid STUN connectivity check request. Ignoring... %s", strerror(errno));
......
...@@ -166,6 +166,37 @@ static gboolean priv_add_local_candidate_pruned (Component *component, NiceCandi ...@@ -166,6 +166,37 @@ static gboolean priv_add_local_candidate_pruned (Component *component, NiceCandi
return TRUE; 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 * Creates a local host candidate for 'component_id' of stream
* 'stream_id'. * 'stream_id'.
...@@ -191,9 +222,7 @@ NiceCandidate *discovery_add_local_host_candidate ( ...@@ -191,9 +222,7 @@ NiceCandidate *discovery_add_local_host_candidate (
if (candidate) { if (candidate) {
NiceUDPSocket *udp_socket = g_slice_new0 (NiceUDPSocket); NiceUDPSocket *udp_socket = g_slice_new0 (NiceUDPSocket);
if (udp_socket) { if (udp_socket) {
/* XXX: implement the foundation assignment as defined in priv_assign_foundation (agent, component, candidate);
* ICE sect 4.1.1.4 ID-15: */
g_snprintf (candidate->foundation, NICE_CANDIDATE_MAX_FOUNDATION, "%u", agent->next_candidate_id++);
candidate->stream_id = stream_id; candidate->stream_id = stream_id;
candidate->component_id = component_id; candidate->component_id = component_id;
candidate->addr = *address; candidate->addr = *address;
...@@ -270,7 +299,7 @@ discovery_add_server_reflexive_candidate ( ...@@ -270,7 +299,7 @@ discovery_add_server_reflexive_candidate (
candidate->priority = candidate->priority =
nice_candidate_ice_priority_full nice_candidate_ice_priority_full
(NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE, 0, component_id); (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->stream_id = stream_id;
candidate->component_id = component_id; candidate->component_id = component_id;
candidate->addr = *address; candidate->addr = *address;
...@@ -280,7 +309,10 @@ discovery_add_server_reflexive_candidate ( ...@@ -280,7 +309,10 @@ discovery_add_server_reflexive_candidate (
candidate->base_addr = base_socket->addr; candidate->base_addr = base_socket->addr;
result = priv_add_local_candidate_pruned (component, candidate); 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 */ /* error: memory allocation, or duplicate candidatet */
nice_candidate_free (candidate), candidate = NULL; nice_candidate_free (candidate), candidate = NULL;
} }
...@@ -320,7 +352,7 @@ discovery_add_peer_reflexive_candidate ( ...@@ -320,7 +352,7 @@ discovery_add_peer_reflexive_candidate (
(NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE, 0, component_id); (NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE, 0, component_id);
candidate->stream_id = stream_id; candidate->stream_id = stream_id;
candidate->component_id = component_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->addr = *address;
candidate->base_addr = base_socket->addr; candidate->base_addr = base_socket->addr;
......
...@@ -46,26 +46,107 @@ ...@@ -46,26 +46,107 @@
* @file stream.c * @file stream.c
* @brief ICE stream functionality * @brief ICE stream functionality
*/ */
Stream * Stream *
stream_new (void) stream_new (guint n_components)
{ {
Stream *stream; Stream *stream;
guint n;
gboolean errors = FALSE;
GSList *modified_list;
Component *component;
stream = g_slice_new0 (Stream); stream = g_slice_new0 (Stream);
stream->component = component_new (COMPONENT_TYPE_RTP); for (n = 0; n < n_components; n++) {
stream->n_components = 1; 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; stream->initial_binding_request_received = FALSE;
return stream; return stream;
} }
void void
stream_free (Stream *stream) 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); 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 ...@@ -59,8 +59,7 @@ struct _Stream
guint id; guint id;
guint n_components; guint n_components;
gboolean initial_binding_request_received; gboolean initial_binding_request_received;
/* XXX: streams can have multiple components */ GSList *components; /* list of components */
Component *component;
gchar local_ufrag[NICE_STREAM_MAX_UFRAG]; gchar local_ufrag[NICE_STREAM_MAX_UFRAG];
gchar local_password[NICE_STREAM_MAX_PWD]; gchar local_password[NICE_STREAM_MAX_PWD];
gchar remote_ufrag[NICE_STREAM_MAX_UFRAG]; gchar remote_ufrag[NICE_STREAM_MAX_UFRAG];
...@@ -68,11 +67,20 @@ struct _Stream ...@@ -68,11 +67,20 @@ struct _Stream
}; };
Stream * Stream *
stream_new (void); stream_new (guint n_components);
void void
stream_free (Stream *stream); 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 G_END_DECLS
#endif /* _NICE_STREAM_H */ #endif /* _NICE_STREAM_H */
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
* *
* Contributors: * Contributors:
* Dafydd Harries, Collabora Ltd. * Dafydd Harries, Collabora Ltd.
* Kai Vehmanen, Nokia
* *
* Alternatively, the contents of this file may be used under the terms of the * 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 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
...@@ -62,8 +63,8 @@ main (void) ...@@ -62,8 +63,8 @@ main (void)
nice_agent_add_local_address (agent, &addr); nice_agent_add_local_address (agent, &addr);
g_assert (nice_agent_add_stream (agent, 1) == 1); 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, 10) == 2);
g_assert (nice_agent_add_stream (agent, 1) == 3); g_assert (nice_agent_add_stream (agent, 2) == 3);
g_assert (NULL != agent->streams); g_assert (NULL != agent->streams);
......
...@@ -42,10 +42,12 @@ ...@@ -42,10 +42,12 @@
#include "agent.h" #include "agent.h"
#include "udp-bsd.h" #include "udp-bsd.h"
static const guint test_component_id = 1;
static NiceComponentState global_lagent_state = NICE_COMPONENT_STATE_LAST; static NiceComponentState global_lagent_state = NICE_COMPONENT_STATE_LAST;
static NiceComponentState global_ragent_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 GMainLoop *global_mainloop = NULL;
static gboolean global_lagent_gathering_done = FALSE; static gboolean global_lagent_gathering_done = FALSE;
static gboolean global_ragent_gathering_done = FALSE; static gboolean global_ragent_gathering_done = FALSE;
...@@ -104,12 +106,11 @@ static void cb_candidate_gathering_done(NiceAgent *agent, gpointer data) ...@@ -104,12 +106,11 @@ static void cb_candidate_gathering_done(NiceAgent *agent, gpointer data)
(void)agent; (void)agent;
} }
#if 0
static void cb_component_state_changed(NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data) 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_debug ("%s: %p", __func__, data);
g_assert (test_component_id == component_id);
if ((int)data == 1) if ((int)data == 1)
global_lagent_state = state; global_lagent_state = state;
else if ((int)data == 2) else if ((int)data == 2)
...@@ -132,12 +133,44 @@ static void cb_component_state_changed(NiceAgent *agent, guint stream_id, guint ...@@ -132,12 +133,44 @@ static void cb_component_state_changed(NiceAgent *agent, guint stream_id, guint
/* XXX: dear compiler, these are for you: */ /* XXX: dear compiler, these are for you: */
(void)agent; (void)stream_id; (void)data; (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, static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint component_id,
gchar *lfoundation, gchar* rfoundation, gpointer data) gchar *lfoundation, gchar* rfoundation, gpointer data)
{ {
g_debug ("%s: %p", __func__, data); g_debug ("%s: %p", __func__, data);
g_assert (test_component_id == component_id);
if ((int)data == 1) if ((int)data == 1)
++global_lagent_cands; ++global_lagent_cands;
...@@ -145,16 +178,16 @@ static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint compon ...@@ -145,16 +178,16 @@ static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint compon
++global_ragent_cands; ++global_ragent_cands;
/* XXX: dear compiler, these are for you: */ /* 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, static void cb_new_candidate(NiceAgent *agent, guint stream_id, guint component_id,
gchar *foundation, gpointer data) gchar *foundation, gpointer data)
{ {
g_debug ("%s: %p", __func__, data); g_debug ("%s: %p", __func__, data);
g_assert (test_component_id == component_id);
/* XXX: dear compiler, these are for you: */ /* 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) 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 ...@@ -170,23 +203,40 @@ static void cb_initial_binding_request_received(NiceAgent *agent, guint stream_i
(void)agent; (void)stream_id; (void)data; (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) 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) */ NiceCandidateDesc cdes = { /* candidate description (no ports) */
(gchar *)"1", /* foundation */ (gchar *)"1", /* foundation */
test_component_id, 0, /* component-id; filled later */
NICE_CANDIDATE_TRANSPORT_UDP, /* transport */ NICE_CANDIDATE_TRANSPORT_UDP, /* transport */
100000, /* priority */ 100000, /* priority */
NULL, /* address */ NULL, /* address */
NICE_CANDIDATE_TYPE_HOST, /* type */ NICE_CANDIDATE_TYPE_HOST, /* type */
NULL /* base-address */ NULL /* base-address */
}; };
GSList *cands, *i; GSList *cands;
guint ls_id, rs_id; guint ls_id, rs_id;
global_lagent_state = NICE_COMPONENT_STATE_LAST; /* step: initialize variables modified by the callbacks */
global_ragent_state = NICE_COMPONENT_STATE_LAST; global_components_ready = 0;
global_components_ready_exit = 4;
global_components_failed = 0;
global_components_failed_exit = 4;
global_lagent_gathering_done = FALSE; global_lagent_gathering_done = FALSE;
global_ragent_gathering_done = FALSE; global_ragent_gathering_done = FALSE;
global_lagent_ibr_received = global_lagent_ibr_received =
...@@ -197,9 +247,9 @@ static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *bas ...@@ -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 (lagent), "controlling-mode", TRUE, NULL);
g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL);
/* step: add one stream, with one component, to each agent */ /* step: add one stream, with RTP+RTCP components, to each agent */
ls_id = nice_agent_add_stream (lagent, 1); ls_id = nice_agent_add_stream (lagent, 2);
rs_id = nice_agent_add_stream (ragent, 1); rs_id = nice_agent_add_stream (ragent, 2);
g_assert (ls_id > 0); g_assert (ls_id > 0);
g_assert (rs_id > 0); g_assert (rs_id > 0);
...@@ -214,25 +264,19 @@ static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *bas ...@@ -214,25 +264,19 @@ static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *bas
} }
/* step: find out the local candidates of each agent */ /* 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); priv_get_local_addr (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, &raddr);
for (i = cands; i; i = i->next) { g_debug ("test-fullmode: local RTP port R %u", raddr.port);
NiceCandidate *cand = i->data;
if (cand) { priv_get_local_addr (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, &laddr);
g_debug ("test-fullmode: local port R %u", cand->addr.port); g_debug ("test-fullmode: local RTP port L %u", laddr.port);
raddr = cand->addr;
} 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);
g_slist_free (cands);
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..."); g_debug ("test-fullmode: Got local candidates...");
/* step: pass the remote candidates to agents */ /* step: pass the remote candidates to agents */
...@@ -246,10 +290,17 @@ static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *bas ...@@ -246,10 +290,17 @@ static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *bas
nice_agent_set_remote_credentials (lagent, nice_agent_set_remote_credentials (lagent,
ls_id, ufrag, password); ls_id, ufrag, password);
} }
cdes.component_id = NICE_COMPONENT_TYPE_RTP;
cdes.addr = &raddr; cdes.addr = &raddr;
nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, cands); nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, cands);
cdes.addr = &laddr; cdes.addr = &laddr;
nice_agent_set_remote_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, cands); 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_slist_free (cands);
g_debug ("test-fullmode: Set properties, next running mainloop until connectivity checks succeed..."); 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 ...@@ -263,8 +314,8 @@ static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *bas
g_assert (global_ragent_ibr_received == TRUE); g_assert (global_ragent_ibr_received == TRUE);
/* note: verify that correct number of local candidates were reported */ /* note: verify that correct number of local candidates were reported */
g_assert (global_lagent_cands == 1); g_assert (global_lagent_cands == 2);
g_assert (global_ragent_cands == 1); g_assert (global_ragent_cands == 2);
/* note: test payload send and receive */ /* note: test payload send and receive */
global_ragent_read = 0; global_ragent_read = 0;
...@@ -287,7 +338,7 @@ static int run_full_test_wrong_password (NiceAgent *lagent, NiceAgent *ragent, N ...@@ -287,7 +338,7 @@ static int run_full_test_wrong_password (NiceAgent *lagent, NiceAgent *ragent, N
NiceAddress laddr, raddr; NiceAddress laddr, raddr;
NiceCandidateDesc cdes = { /* candidate description (no ports) */ NiceCandidateDesc cdes = { /* candidate description (no ports) */
(gchar *)"1", /* foundation */ (gchar *)"1", /* foundation */
test_component_id, NICE_COMPONENT_TYPE_RTP,
NICE_CANDIDATE_TRANSPORT_UDP, /* transport */ NICE_CANDIDATE_TRANSPORT_UDP, /* transport */
100000, /* priority */ 100000, /* priority */
NULL, /* address */ NULL, /* address */
...@@ -297,6 +348,10 @@ static int run_full_test_wrong_password (NiceAgent *lagent, NiceAgent *ragent, N ...@@ -297,6 +348,10 @@ static int run_full_test_wrong_password (NiceAgent *lagent, NiceAgent *ragent, N
GSList *cands, *i; GSList *cands, *i;
guint ls_id, rs_id; 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_lagent_state =
global_ragent_state = NICE_COMPONENT_STATE_LAST; global_ragent_state = NICE_COMPONENT_STATE_LAST;
global_lagent_gathering_done = global_lagent_gathering_done =
...@@ -387,7 +442,7 @@ static int run_full_test_control_conflict (NiceAgent *lagent, NiceAgent *ragent, ...@@ -387,7 +442,7 @@ static int run_full_test_control_conflict (NiceAgent *lagent, NiceAgent *ragent,
NiceAddress laddr, raddr; NiceAddress laddr, raddr;
NiceCandidateDesc cdes = { /* candidate description (no ports) */ NiceCandidateDesc cdes = { /* candidate description (no ports) */
(gchar *)"1", /* foundation */ (gchar *)"1", /* foundation */
test_component_id, NICE_COMPONENT_TYPE_RTP,
NICE_CANDIDATE_TRANSPORT_UDP, /* transport */ NICE_CANDIDATE_TRANSPORT_UDP, /* transport */
100000, /* priority */ 100000, /* priority */
NULL, /* address */ NULL, /* address */
...@@ -397,6 +452,10 @@ static int run_full_test_control_conflict (NiceAgent *lagent, NiceAgent *ragent, ...@@ -397,6 +452,10 @@ static int run_full_test_control_conflict (NiceAgent *lagent, NiceAgent *ragent,
GSList *cands, *i; GSList *cands, *i;
guint ls_id, rs_id; 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_lagent_state =
global_ragent_state = NICE_COMPONENT_STATE_LAST; global_ragent_state = NICE_COMPONENT_STATE_LAST;
global_lagent_gathering_done = 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