Commit b9ba0195 authored by Kai Vehmanen's avatar Kai Vehmanen

Added initial full-mode extensions to the API. Added support for gathering...

Added initial full-mode extensions to the API. Added support for gathering candidates using STUN binding discovery API.

darcs-hash:20070502142419-77cd4-6e295bdf89c80a6cdab778fe25e26c9e780ce2b5.gz
parent cde5ed64
# component-status-changed # component-status-changed
VOID:UINT,UINT,UINT VOID:UINT,UINT,UINT
# candidate-gathering-done
VOID:VOID
...@@ -36,17 +36,67 @@ ...@@ -36,17 +36,67 @@
*/ */
#include <string.h> #include <string.h>
#include <errno.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/socket.h>
#ifndef _BSD_SOURCE
#error "timercmp() macros needed"
#endif
#include <sys/time.h> /* timercmp() macro, BSD */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <glib.h> #include <glib.h>
#include "stun/bind.h"
#include "stun.h" #include "stun.h"
#include "udp.h" #include "udp.h"
#include "component.h"
#include "agent.h" #include "agent.h"
#include "agent-signals-marshal.h" #include "agent-signals-marshal.h"
#include "stream.h"
typedef enum
{
NICE_CHECK_WAITING = 1,
NICE_CHECK_IN_PROGRESS,
NICE_CHECK_SUCCEEDED,
NICE_CHECK_FAILED,
NICE_CHECK_FROZEN
} NiceCheckState;
typedef struct _CandidateDiscoveryUDP CandidateDiscoveryUDP;
struct _CandidateDiscoveryUDP
{
NiceAgent *agent; /* back pointer to owner */
NiceCandidateType type; /* candidate type STUN or TURN */
int socket; /* existing socket to use */
gchar *server_addr; /* STUN/TURN server address */
NiceAddress *interface; /* Address of local interface */
stun_bind_t *ctx;
GTimeVal next_tick; /* next tick timestamp */
gboolean pending; /* is discovery in progress? */
gboolean done; /* is discovery complete? */
guint stream_id;
guint component_id;
};
typedef struct _CandidatePair CandidatePair;
struct _CandidatePair
{
NiceAgent *agent; /* back pointer to owner */
guint stream_id;
guint component_id;
NiceCandidate *local;
NiceCandidate *remote;
gchar *foundation;
NiceCheckState state;
};
#include "stream.h"
typedef enum typedef enum
{ {
...@@ -55,19 +105,26 @@ typedef enum ...@@ -55,19 +105,26 @@ typedef enum
} CheckListState; } CheckListState;
#define NICE_AGENT_TIMER_TA_DEFAULT 20; /* timer Ta, msecs */
#define NICE_AGENT_TIMER_TR_DEFAULT 15000; /* timer Tr, msecs */
G_DEFINE_TYPE (NiceAgent, nice_agent, G_TYPE_OBJECT); G_DEFINE_TYPE (NiceAgent, nice_agent, G_TYPE_OBJECT);
enum enum
{ {
PROP_SOCKET_FACTORY = 1, PROP_SOCKET_FACTORY = 1,
PROP_STUN_SERVER PROP_STUN_SERVER,
PROP_STUN_SERVER_PORT,
PROP_TURN_SERVER,
PROP_TURN_SERVER_PORT
}; };
enum enum
{ {
SIGNAL_COMPONENT_STATE_CHANGED, SIGNAL_COMPONENT_STATE_CHANGED,
SIGNAL_CANDIDATE_GATHERING_DONE,
N_SIGNALS, N_SIGNALS,
}; };
...@@ -164,6 +221,32 @@ nice_agent_class_init (NiceAgentClass *klass) ...@@ -164,6 +221,32 @@ nice_agent_class_init (NiceAgentClass *klass)
NULL, NULL,
G_PARAM_READWRITE)); G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_STUN_SERVER_PORT,
g_param_spec_uint (
"stun-server-port",
"STUN server port",
"The STUN server used to obtain server-reflexive candidates",
1, 65536,
3478, /* default port */
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_STUN_SERVER,
g_param_spec_string (
"turn-server",
"TURN server",
"The TURN server used to obtain relay candidates",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_STUN_SERVER_PORT,
g_param_spec_uint (
"turn-server-port",
"TURN server port",
"The STUN server used to obtain relay candidates",
1, 65536,
3478, /* no default port for TURN, use the STUN default*/
G_PARAM_READWRITE));
/* install signals */ /* install signals */
signals[SIGNAL_COMPONENT_STATE_CHANGED] = signals[SIGNAL_COMPONENT_STATE_CHANGED] =
...@@ -179,6 +262,19 @@ nice_agent_class_init (NiceAgentClass *klass) ...@@ -179,6 +262,19 @@ nice_agent_class_init (NiceAgentClass *klass)
3, 3,
G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
G_TYPE_INVALID); G_TYPE_INVALID);
signals[SIGNAL_CANDIDATE_GATHERING_DONE] =
g_signal_new (
"candidate-gathering-done",
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
0,
NULL,
NULL,
agent_marshal_VOID__VOID,
G_TYPE_NONE,
0,
G_TYPE_INVALID);
} }
...@@ -187,6 +283,13 @@ nice_agent_init (NiceAgent *agent) ...@@ -187,6 +283,13 @@ nice_agent_init (NiceAgent *agent)
{ {
agent->next_candidate_id = 1; agent->next_candidate_id = 1;
agent->next_stream_id = 1; agent->next_stream_id = 1;
agent->discovery_unsched_items = 0;
/* XXX: make configurable */
agent->full_mode = TRUE;
agent->discovery_list = NULL;
agent->rng = nice_rng_new (); agent->rng = nice_rng_new ();
} }
...@@ -224,7 +327,16 @@ nice_agent_get_property ( ...@@ -224,7 +327,16 @@ nice_agent_get_property (
break; break;
case PROP_STUN_SERVER: case PROP_STUN_SERVER:
g_value_set_string (value, agent->stun_server); g_value_set_string (value, agent->stun_server_ip);
case PROP_STUN_SERVER_PORT:
g_value_set_uint (value, agent->stun_server_port);
case PROP_TURN_SERVER:
g_value_set_string (value, agent->turn_server_ip);
case PROP_TURN_SERVER_PORT:
g_value_set_uint (value, agent->turn_server_port);
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
...@@ -248,7 +360,15 @@ nice_agent_set_property ( ...@@ -248,7 +360,15 @@ nice_agent_set_property (
break; break;
case PROP_STUN_SERVER: case PROP_STUN_SERVER:
agent->stun_server = g_value_dup_string (value); agent->stun_server_ip = g_value_dup_string (value);
break;
case PROP_STUN_SERVER_PORT:
agent->stun_server_port = g_value_get_uint (value);
break;
case PROP_TURN_SERVER:
agent->turn_server_ip = g_value_dup_string (value);
break; break;
default: default:
...@@ -256,7 +376,34 @@ nice_agent_set_property ( ...@@ -256,7 +376,34 @@ nice_agent_set_property (
} }
} }
static int
nice_agent_get_local_host_candidate_sockfd (
NiceAgent *agent,
guint stream_id,
guint component_id,
NiceAddress *address)
{
Component *component;
GSList *i;
if (!find_component (agent, stream_id, component_id, NULL, &component)) {
return -1;
}
for (i = component->local_candidates; i; i = i->next) {
NiceCandidate *candidate = i->data;
/* note nice_address_equal() also compares the ports and
* we don't want that here */
if (address->type == NICE_ADDRESS_TYPE_IPV4 &&
address->addr_ipv4 == candidate->base_addr.addr_ipv4)
return candidate->sock.fileno;
}
return -1;
}
static void static void
nice_agent_add_local_host_candidate ( nice_agent_add_local_host_candidate (
NiceAgent *agent, NiceAgent *agent,
...@@ -278,6 +425,8 @@ nice_agent_add_local_host_candidate ( ...@@ -278,6 +425,8 @@ nice_agent_add_local_host_candidate (
candidate->base_addr = *address; candidate->base_addr = *address;
component->local_candidates = g_slist_append (component->local_candidates, component->local_candidates = g_slist_append (component->local_candidates,
candidate); candidate);
candidate->priority =
0x1000000 * 126 + 0x100 * 0 + 256 - component_id; /* sect:4.1.2.1(-14) */
/* generate username/password */ /* generate username/password */
nice_rng_generate_bytes_print (agent->rng, 8, candidate->username); nice_rng_generate_bytes_print (agent->rng, 8, candidate->username);
...@@ -293,6 +442,271 @@ nice_agent_add_local_host_candidate ( ...@@ -293,6 +442,271 @@ nice_agent_add_local_host_candidate (
candidate->base_addr = candidate->sock.addr; candidate->base_addr = candidate->sock.addr;
} }
/* compiles but is not called yet */
static void
nice_agent_generate_username_and_password(NiceCandidate *candidate)
{
NiceRNG *rng;
/* generate username/password */
rng = nice_rng_new ();
nice_rng_generate_bytes_print (rng, 8, candidate->username);
nice_rng_generate_bytes_print (rng, 8, candidate->password);
nice_rng_free (rng);
}
static void
nice_agent_add_server_reflexive_candidate (
NiceAgent *agent,
guint stream_id,
guint component_id,
NiceAddress *address)
{
NiceCandidate *candidate;
Component *component;
if (!find_component (agent, stream_id, component_id, NULL, &component))
return;
candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE);
candidate->id = agent->next_candidate_id++;
candidate->stream_id = stream_id;
candidate->component_id = component_id;
candidate->addr = *address;
candidate->base_addr = *address;
component->local_candidates = g_slist_append (component->local_candidates,
candidate);
candidate->priority =
0x1000000 * 125 + 0x100 * 0 + 256 - component_id; /* sect:4.1.2.1(-14) */
/* generate username/password */
nice_agent_generate_username_and_password (candidate);
/* XXX: how to link to the socket of a local candidate? */
#if 0
candidate->base_addr = candidate->sock.addr;
#endif
}
static void nice_agent_free_discovery_candidate_udp (gpointer data, gpointer user_data)
{
CandidateDiscoveryUDP *cand_udp = data;
g_free (cand_udp->server_addr);
g_slice_free (CandidateDiscoveryUDP, cand_udp);
}
static void priv_signal_component_state_gathering (NiceAgent *agent, guint stream_id, guint component_id)
{
Component *component;
if (!find_component (agent, stream_id, component_id, NULL, &component))
return;
if (component->state != NICE_COMPONENT_STATE_GATHERING) {
component->state = NICE_COMPONENT_STATE_GATHERING;
g_signal_emit (agent, signals[SIGNAL_COMPONENT_STATE_CHANGED], 0,
stream_id, component_id, component->state);
}
}
#if 0
static void priv_signal_component_state_connecting (NiceAgent *agent, guint stream_id, guint component_id)
{
Component *component;
if (!find_component (agent, stream_id, component_id, NULL, &component))
return;
if (component->state != NICE_COMPONENT_STATE_CONNECTING) {
component->state = NICE_COMPONENT_STATE_CONNECTING;
g_signal_emit (agent, signals[SIGNAL_COMPONENT_STATE_CHANGED], 0,
stream_id, component_id, component->state);
}
}
#endif
/**
* Timer callback that handles scheduling new candidate discovery
* processes (paced by the Ta timer), and handles running of the
* existing discovery processes.
*
* This function is designed for the g_timeout_add() interface.
*
* @return will return FALSE when no more pending timers.
*/
static gboolean nice_agent_discovery_tick (gpointer pointer)
{
CandidateDiscoveryUDP *cand_udp;
NiceAgent *agent = pointer;
GSList *i;
int not_done = 0;
g_debug ("check tick with list %p (1)", agent->discovery_list);
for (i = agent->discovery_list; i ; i = i->next) {
cand_udp = i->data;
if (cand_udp->pending != TRUE) {
cand_udp->pending = TRUE;
if (agent->discovery_unsched_items)
--agent->discovery_unsched_items;
g_debug ("scheduling cand type %u addr %s and socket %d.\n", cand_udp->type, cand_udp->server_addr, cand_udp->socket);
if (cand_udp->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE) {
struct sockaddr_in stun_server;
memset (&stun_server, 0, sizeof(stun_server));
/* XXX: using hardcoded server address for now */
stun_server.sin_addr.s_addr = inet_addr("127.0.0.1");
stun_server.sin_port = htons(3478);
int res;
res = stun_bind_start (&cand_udp->ctx, cand_udp->socket,
(struct sockaddr*)&stun_server, sizeof(stun_server));
if (res == 0) {
/* case: success, start waiting for the result */
g_get_current_time (&cand_udp->next_tick);
priv_signal_component_state_gathering (agent,
cand_udp->stream_id,
cand_udp->component_id);
}
else {
/* case: error in starting discovery, start the next discovery */
cand_udp->done = TRUE;
continue;
}
}
else
/* allocate relayed candidates */
g_assert_not_reached ();
++not_done;
}
if (cand_udp->done != TRUE) {
struct sockaddr_in mapped_addr;
socklen_t socklen = sizeof(mapped_addr);
GTimeVal now;
g_get_current_time (&now);
/* note: macro from sys/time.h but compatible with GTimeVal */
if (timercmp(&cand_udp->next_tick, &now, <)) {
int res = stun_bind_resume (cand_udp->ctx, (struct sockaddr*)&mapped_addr, &socklen);
if (res == 0) {
/* case: discovery process succesfully completed */
NiceAddress *niceaddr;
niceaddr = nice_address_new();
niceaddr->type = NICE_ADDRESS_TYPE_IPV4;
niceaddr->addr_ipv4 = ntohl(mapped_addr.sin_addr.s_addr);
niceaddr->port = ntohs(mapped_addr.sin_port);
{
gchar ip[NICE_ADDRESS_STRING_LEN];
nice_address_to_string (niceaddr, ip);
g_debug("%s: our public contact address is %s\n",
__func__, ip);
}
/* XXX: add
* g_signal_emit (agent, signals[SIGNAL_NEW_CANDIDATE], 0); */
nice_agent_add_server_reflexive_candidate (
cand_udp->agent,
cand_udp->stream_id,
cand_udp->component_id,
niceaddr);
nice_address_free (niceaddr);
cand_udp->done = TRUE;
}
else if (res == EAGAIN) {
/* case: not ready complete, so schedule next timeout */
unsigned int timeout = stun_bind_timeout (cand_udp->ctx);
g_get_current_time (&cand_udp->next_tick);
g_time_val_add (&cand_udp->next_tick, timeout * 10);
/* note: macro from sys/time.h but compatible with GTimeVal */
if (timercmp(&cand_udp->next_tick, &agent->next_check_tv, <)) {
agent->next_check_tv = cand_udp->next_tick;
}
++not_done;
}
else {
/* case: error, abort processing */
cand_udp->done = TRUE;
}
}
}
}
if (not_done == 0) {
g_debug ("Candidate gathering FINISHED, stopping Ta timer.");
g_slist_foreach (agent->discovery_list, nice_agent_free_discovery_candidate_udp, NULL);
g_slist_free (agent->discovery_list),
agent->discovery_list = NULL;
g_signal_emit (agent, signals[SIGNAL_CANDIDATE_GATHERING_DONE], 0);
/* note: no pending timers, return FALSE to stop timer */
return FALSE;
}
return TRUE;
}
static void nice_agent_schedule_discovery (NiceAgent *agent)
{
if (agent->discovery_list) {
GTimeVal now;
/* XXX: make timeout Ta configurable */
guint next = NICE_AGENT_TIMER_TA_DEFAULT;
if (agent->discovery_unsched_items == 0)
next = (guint)-1;
/* XXX: send a component state-change, but, but, how do we
* actually do this? back to the drawing board... */
/*
* Component *component;
* if (!find_component (agent, stream_id, component_id, &stream, &component))
* return 0;
*
* component->state = NICE_COMPONENT_STATE_GATHERING;
*
* g_signal_emit (agent, signals[SIGNAL_COMPONENT_STATE_CHANGED], 0,
* cand_stream->id, component->id, component->state);
*/
nice_agent_discovery_tick (agent);
g_get_current_time (&now);
guint msecs = (agent->next_check_tv.tv_sec - now.tv_sec) * 1000;
msecs += (agent->next_check_tv.tv_usec - now.tv_usec) / 1000;
if (msecs < next)
next = msecs;
g_debug ("Scheduling a timeout of %u msec.", next);
g_timeout_add (next, nice_agent_discovery_tick, agent);
}
}
/** /**
* nice_agent_add_stream: * nice_agent_add_stream:
...@@ -313,27 +727,60 @@ nice_agent_add_stream ( ...@@ -313,27 +727,60 @@ nice_agent_add_stream (
GSList *i; GSList *i;
g_assert (n_components == 1); g_assert (n_components == 1);
if (!agent->streams) {
/* note: this contains a Y2038 issue */
agent->next_check_tv.tv_sec =
agent->next_check_tv.tv_usec = (long)-1;
}
stream = stream_new (); stream = stream_new ();
stream->id = agent->next_stream_id++; stream->id = agent->next_stream_id++;
agent->streams = g_slist_append (agent->streams, stream); agent->streams = g_slist_append (agent->streams, stream);
/* generate a local host candidate for each local address */ /* generate a local host candidate for each local address */
if (agent->full_mode) {
g_debug ("In FULL mode, starting candidate gathering.\n");
}
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;
CandidateDiscoveryUDP *cand_udp;
int sockfd;
nice_agent_add_local_host_candidate (agent, stream->id, nice_agent_add_local_host_candidate (agent, stream->id,
stream->component->id, addr); stream->component->id, addr);
/* XXX: need to check for redundant candidates? */ if (agent->full_mode) {
/* later: send STUN requests to obtain server-reflexive candidates */ sockfd = nice_agent_get_local_host_candidate_sockfd (agent, stream->id, stream->component->id, addr);
/* XXX: need to check for redundant candidates? -> not yet,
* this is done later on */
cand_udp = g_slice_new0 (CandidateDiscoveryUDP);
cand_udp->type = NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE;
cand_udp->socket = sockfd;
cand_udp->server_addr = g_strdup ("127.0.0.1" /*"stunserver.org"*/);
cand_udp->interface = addr;
cand_udp->stream_id = stream->id;
cand_udp->component_id = stream->component->id;
cand_udp->agent = agent;
g_debug ("Adding srv-rflx candidate %p\n", cand_udp);
agent->discovery_list = g_slist_append (agent->discovery_list, cand_udp);
++agent->discovery_unsched_items;
}
/* XXX-later: send STUN requests to obtain server-reflexive candidates */
} }
if (agent->discovery_list)
nice_agent_schedule_discovery (agent);
return stream->id; return stream->id;
} }
/** /**
* nice_agent_remove_stream: * nice_agent_remove_stream:
* @agent: a NiceAgent * @agent: a NiceAgent
...@@ -383,6 +830,98 @@ nice_agent_add_local_address (NiceAgent *agent, NiceAddress *addr) ...@@ -383,6 +830,98 @@ nice_agent_add_local_address (NiceAgent *agent, NiceAddress *addr)
*/ */
} }
static gboolean nice_agent_conn_check_tick (gpointer pointer)
{
/* XXX: placeholder, implementation not done */
g_debug ("%s: stopping timer", G_STRFUNC);
return FALSE;
}
/**
* Schedules the next timer tick for connectivity checks.
*/
static void priv_schedule_conn_checks (NiceAgent *agent)
{
/* XXX: placeholder, implementation not done */
g_timeout_add (1, nice_agent_conn_check_tick, agent);
}
/**
* Forms new candidate pairs by matching the new remote candidate
* 'remote_cand' with all existing local candidates of 'component'.
* Implements the logic described in sect 5.7.1 of ICE -15 spec.
*/
static void priv_add_conn_checks (NiceAgent *agent, Component *component, NiceCandidate *remote_cand)
{
GSList *i;
for (i = component->local_candidates; i ; i = i->next) {
/* XXX: steps:
* - form a new candidate pair item (CandidatePair)
* - add it, filtered/pruned, to the check list
* - schedule the next timeout (priv_schedule_conn_checks())
*/
/* XXX: to keep the compiler happy until implementation is done */
NiceCandidate *cand = i->data;
cand = NULL;
}
priv_schedule_conn_checks (agent);
}
static void priv_add_remote_candidate (
NiceAgent *agent,
guint stream_id,
guint component_id,
NiceCandidateType type,
const NiceAddress *addr,
const NiceAddress *related_addr,
NiceCandidateTransport transport,
guint32 priority,
const gchar *username,
const gchar *password,
const gchar *foundation)
{
Component *component;
NiceCandidate *candidate;
if (!find_component (agent, stream_id, component_id, NULL, &component))
return;
candidate = nice_candidate_new (type);
candidate->stream_id = stream_id;
candidate->component_id = component_id;
/* note: always zero, foundation used to identify remote cands */
candidate->id = 0;
candidate->type = type;
if (addr)
candidate->addr = *addr;
if (related_addr)
candidate->base_addr = *related_addr;
candidate->transport = transport;
/* XXX: ugh, ugh, fixed size fields */
if (username)
strncpy (candidate->username, username, sizeof (candidate->username));
if (password)
strncpy (candidate->password, password, sizeof (candidate->password));
if (foundation)
candidate->foundation = g_strdup (foundation);
component->remote_candidates = g_slist_append (component->remote_candidates,
candidate);
priv_add_conn_checks (agent, component, candidate);
}
/** /**
* nice_agent_add_remote_candidate * nice_agent_add_remote_candidate
* @agent: a NiceAgent * @agent: a NiceAgent
...@@ -406,27 +945,55 @@ nice_agent_add_remote_candidate ( ...@@ -406,27 +945,55 @@ nice_agent_add_remote_candidate (
const gchar *username, const gchar *username,
const gchar *password) const gchar *password)
{ {
NiceCandidate *candidate; priv_add_remote_candidate (agent,
Component *component; stream_id,
component_id,
if (!find_component (agent, stream_id, component_id, NULL, &component)) type,
return; addr,
NULL,
candidate = nice_candidate_new (type); NICE_CANDIDATE_TRANSPORT_UDP,
candidate->stream_id = stream_id; 0,
candidate->component_id = component_id; username,
/* XXX: do remote candidates need IDs? */ password,
candidate->id = 0; NULL);
candidate->addr = *addr;
strncpy (candidate->username, username, sizeof (candidate->username)); /* later: for each component, generate a new check with the new
strncpy (candidate->password, password, sizeof (candidate->password)); candidate */
component->remote_candidates = g_slist_append (component->remote_candidates,
candidate);
/* later: for each component, generate a new check with the new candidate */
} }
/**
* nice_agent_set_remote_candidates
* @agent: a NiceAgent
* @stream_id: the ID of the stream the candidate is for
* @component_id: the ID of the component the candidate is for
* @candidates: a list of NiceCandidateDesc items describing the candidates
*
* Sets the remote candidates for a component of a stream. Replaces
* any existing remote candidates.
**/
void
nice_agent_set_remote_candidates (NiceAgent *agent, guint stream_id, guint component_id, GSList *candidates)
{
GSList *i;
/* XXX: clean up existing remote candidates, and abort any
* connectivity checks using these candidates */
for (i = candidates; i; i = i->next) {
NiceCandidateDesc *d = (NiceCandidateDesc*) i->data;
priv_add_remote_candidate (agent,
stream_id,
component_id,
d->type,
d->addr,
d->related_addr,
d->transport,
d->priority,
NULL,
NULL,
d->foundation);
}
}
#if 0 #if 0
static NiceCandidate * static NiceCandidate *
...@@ -505,6 +1072,8 @@ _handle_stun_binding_request ( ...@@ -505,6 +1072,8 @@ _handle_stun_binding_request (
* --> send error * --> send error
*/ */
/* XXX-KV: update to use Remi's implementation */
attr = stun_message_find_attribute (msg, STUN_ATTRIBUTE_USERNAME); attr = stun_message_find_attribute (msg, STUN_ATTRIBUTE_USERNAME);
if (attr == NULL) if (attr == NULL)
...@@ -542,8 +1111,8 @@ _handle_stun_binding_request ( ...@@ -542,8 +1111,8 @@ _handle_stun_binding_request (
#if 0 #if 0
/* usernames match; check address */ /* usernames match; check address */
if (rtmp->addr.addr_ipv4 == ntohs (from.sin_addr.s_addr) && if (rtmp->addr.addr_ipv4 == ntohl (from.sin_addr.s_addr) &&
rtmp->port == ntohl (from.sin_port)) rtmp->port == ntohs (from.sin_port))
{ {
/* this is a candidate we know about, just send a reply */ /* this is a candidate we know about, just send a reply */
/* is candidate pair active now? */ /* is candidate pair active now? */
...@@ -586,6 +1155,8 @@ RESPOND: ...@@ -586,6 +1155,8 @@ RESPOND:
guint len; guint len;
gchar *packed; gchar *packed;
/* XXX-KV: update to use Remi's implementation */
response = stun_message_new (STUN_MESSAGE_BINDING_RESPONSE, response = stun_message_new (STUN_MESSAGE_BINDING_RESPONSE,
msg->transaction_id, 2); msg->transaction_id, 2);
response->attributes[0] = stun_attribute_mapped_address_new ( response->attributes[0] = stun_attribute_mapped_address_new (
...@@ -607,6 +1178,8 @@ RESPOND: ...@@ -607,6 +1178,8 @@ RESPOND:
guint len; guint len;
gchar *packed; gchar *packed;
/* XXX-KV: update to use Remi's implementation */
extra = stun_message_new (STUN_MESSAGE_BINDING_REQUEST, extra = stun_message_new (STUN_MESSAGE_BINDING_REQUEST,
NULL, 1); NULL, 1);
...@@ -657,6 +1230,8 @@ ERROR: ...@@ -657,6 +1230,8 @@ ERROR:
guint len; guint len;
gchar *packed; gchar *packed;
/* XXX-KV: update to use Remi's implementation */
response = stun_message_new (STUN_MESSAGE_BINDING_ERROR_RESPONSE, response = stun_message_new (STUN_MESSAGE_BINDING_ERROR_RESPONSE,
msg->transaction_id, 0); msg->transaction_id, 0);
len = stun_message_pack (response, &packed); len = stun_message_pack (response, &packed);
...@@ -763,6 +1338,8 @@ _nice_agent_recv ( ...@@ -763,6 +1338,8 @@ _nice_agent_recv (
/* connectivity checks are described in ICE-13 §7. */ /* connectivity checks are described in ICE-13 §7. */
StunMessage *msg; StunMessage *msg;
/* XXX-KV: update to use Remi's implementation */
msg = stun_message_unpack (len, buf); msg = stun_message_unpack (len, buf);
if (msg != NULL) if (msg != NULL)
...@@ -1052,6 +1629,9 @@ nice_agent_get_remote_candidates ( ...@@ -1052,6 +1629,9 @@ nice_agent_get_remote_candidates (
if (!find_component (agent, stream_id, component_id, NULL, &component)) if (!find_component (agent, stream_id, component_id, NULL, &component))
return NULL; return NULL;
/* XXX: should we expose NiceCandidate to the client, or should
* we instead return a list of NiceCandidateDesc's? */
return g_slist_copy (component->remote_candidates); return g_slist_copy (component->remote_candidates);
} }
...@@ -1062,6 +1642,12 @@ nice_agent_dispose (GObject *object) ...@@ -1062,6 +1642,12 @@ nice_agent_dispose (GObject *object)
GSList *i; GSList *i;
NiceAgent *agent = NICE_AGENT (object); NiceAgent *agent = NICE_AGENT (object);
if (agent->discovery_list) {
g_slist_foreach (agent->discovery_list, nice_agent_free_discovery_candidate_udp, NULL);
g_slist_free (agent->discovery_list),
agent->discovery_list = NULL;
}
for (i = agent->local_addresses; i; i = i->next) for (i = agent->local_addresses; i; i = i->next)
{ {
NiceAddress *a = i->data; NiceAddress *a = i->data;
...@@ -1082,8 +1668,8 @@ nice_agent_dispose (GObject *object) ...@@ -1082,8 +1668,8 @@ nice_agent_dispose (GObject *object)
g_slist_free (agent->streams); g_slist_free (agent->streams);
agent->streams = NULL; agent->streams = NULL;
g_free (agent->stun_server); g_free (agent->stun_server_ip);
agent->stun_server = NULL; agent->stun_server_ip = NULL;
nice_rng_free (agent->rng); nice_rng_free (agent->rng);
agent->rng = NULL; agent->rng = NULL;
...@@ -1200,4 +1786,3 @@ nice_agent_main_context_attach ( ...@@ -1200,4 +1786,3 @@ nice_agent_main_context_attach (
agent->read_func_data = data; agent->read_func_data = data;
return TRUE; return TRUE;
} }
...@@ -71,11 +71,34 @@ G_BEGIN_DECLS ...@@ -71,11 +71,34 @@ G_BEGIN_DECLS
typedef enum typedef enum
{ {
NICE_COMPONENT_STATE_DISCONNECTED, NICE_COMPONENT_STATE_DISCONNECTED, /* no activity scheduled */
NICE_COMPONENT_STATE_CONNECTING, NICE_COMPONENT_STATE_GATHERING, /* gathering local candidates */
NICE_COMPONENT_STATE_CONNECTED, NICE_COMPONENT_STATE_CONNECTING, /* establishing connectivity */
NICE_COMPONENT_STATE_CONNECTED, /* at least one working candidate pair */
NICE_COMPONENT_STATE_READY, /* ICE concluded, candidate pair
selection is now final */
NICE_COMPONENT_STATE_FAILED /* connectivity checks have been completed,
but connectivity was not established */
} NiceComponentState; } NiceComponentState;
typedef enum
{
NICE_COMPONENT_TYPE_RTP = 1,
NICE_COMPONENT_TYPE_RTCP = 2
} NiceComponentType;
typedef struct _NiceCandidateDesc NiceCandidateDesc;
struct _NiceCandidateDesc {
const gchar *foundation;
guint component_id;
NiceCandidateTransport transport;
guint32 priority;
const NiceAddress *addr;
NiceCandidateType type;
const NiceAddress *related_addr; /* optional */
};
typedef struct _NiceAgent NiceAgent; typedef struct _NiceAgent NiceAgent;
typedef void (*NiceAgentRecvFunc) ( typedef void (*NiceAgentRecvFunc) (
...@@ -87,6 +110,7 @@ struct _NiceAgent ...@@ -87,6 +110,7 @@ struct _NiceAgent
GObject parent; GObject parent;
guint next_candidate_id; guint next_candidate_id;
guint next_stream_id; guint next_stream_id;
gboolean full_mode;
NiceUDPSocketFactory *socket_factory; NiceUDPSocketFactory *socket_factory;
GSList *local_addresses; GSList *local_addresses;
GSList *streams; GSList *streams;
...@@ -94,7 +118,14 @@ struct _NiceAgent ...@@ -94,7 +118,14 @@ struct _NiceAgent
GMainContext *main_context; GMainContext *main_context;
NiceAgentRecvFunc read_func; NiceAgentRecvFunc read_func;
gpointer read_func_data; gpointer read_func_data;
gchar *stun_server; GSList *discovery_list;
guint discovery_unsched_items;
GSList *conncheck_list;
gchar *stun_server_ip;
guint stun_server_port;
gchar *turn_server_ip;
guint turn_server_port;
GTimeVal next_check_tv;
NiceRNG *rng; NiceRNG *rng;
}; };
...@@ -133,6 +164,13 @@ nice_agent_add_remote_candidate ( ...@@ -133,6 +164,13 @@ nice_agent_add_remote_candidate (
const gchar *username, const gchar *username,
const gchar *password); const gchar *password);
void
nice_agent_set_remote_candidates (
NiceAgent *agent,
guint stream_id,
guint component_id,
GSList *candidates);
guint guint
nice_agent_recv ( nice_agent_recv (
NiceAgent *agent, NiceAgent *agent,
......
...@@ -65,6 +65,9 @@ nice_candidate_free (NiceCandidate *candidate) ...@@ -65,6 +65,9 @@ nice_candidate_free (NiceCandidate *candidate)
if (candidate->source) if (candidate->source)
g_source_destroy (candidate->source); g_source_destroy (candidate->source);
if (candidate->foundation)
g_free (candidate->foundation);
g_slice_free (NiceCandidate, candidate); g_slice_free (NiceCandidate, candidate);
} }
......
...@@ -50,23 +50,28 @@ typedef enum ...@@ -50,23 +50,28 @@ typedef enum
NICE_CANDIDATE_TYPE_RELAYED, NICE_CANDIDATE_TYPE_RELAYED,
} NiceCandidateType; } NiceCandidateType;
typedef enum
{
NICE_CANDIDATE_TRANSPORT_UDP,
} NiceCandidateTransport;
typedef struct _NiceCandidate NiceCandidate; typedef struct _NiceCandidate NiceCandidate;
struct _NiceCandidate struct _NiceCandidate
{ {
NiceCandidateType type; NiceCandidateType type;
guint id; NiceCandidateTransport transport;
guint id;
NiceAddress addr; NiceAddress addr;
NiceAddress base_addr; NiceAddress base_addr;
guint32 priority; guint32 priority;
guint stream_id; guint stream_id;
guint component_id; guint component_id;
// guint generation; // guint generation;
// gchar *foundation; gchar *foundation; /* note: if NULL, derive foundation from 'id' */
NiceUDPSocket sock; NiceUDPSocket sock;
gchar username[128]; gchar username[128]; /* XXX: why 128 chars? */
gchar password[128]; gchar password[128]; /* XXX: why 128 chars? */
GSource *source; GSource *source;
}; };
......
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