diff options
-rw-r--r-- | agent/agent-signals-marshal.list | 2 | ||||
-rw-r--r-- | agent/agent.c | 647 | ||||
-rw-r--r-- | agent/agent.h | 46 | ||||
-rw-r--r-- | agent/candidate.c | 3 | ||||
-rw-r--r-- | agent/candidate.h | 13 |
5 files changed, 672 insertions, 39 deletions
diff --git a/agent/agent-signals-marshal.list b/agent/agent-signals-marshal.list index 263303e..f1bbfc8 100644 --- a/agent/agent-signals-marshal.list +++ b/agent/agent-signals-marshal.list @@ -1,2 +1,4 @@ # component-status-changed VOID:UINT,UINT,UINT +# candidate-gathering-done +VOID:VOID diff --git a/agent/agent.c b/agent/agent.c index 875b343..b74f1ea 100644 --- a/agent/agent.c +++ b/agent/agent.c @@ -36,17 +36,67 @@ */ #include <string.h> +#include <errno.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 "stun/bind.h" + #include "stun.h" #include "udp.h" +#include "component.h" #include "agent.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 { @@ -55,19 +105,26 @@ typedef enum } 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); enum { PROP_SOCKET_FACTORY = 1, - PROP_STUN_SERVER + PROP_STUN_SERVER, + PROP_STUN_SERVER_PORT, + PROP_TURN_SERVER, + PROP_TURN_SERVER_PORT }; enum { SIGNAL_COMPONENT_STATE_CHANGED, + SIGNAL_CANDIDATE_GATHERING_DONE, N_SIGNALS, }; @@ -164,6 +221,32 @@ nice_agent_class_init (NiceAgentClass *klass) NULL, 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 */ signals[SIGNAL_COMPONENT_STATE_CHANGED] = @@ -179,6 +262,19 @@ nice_agent_class_init (NiceAgentClass *klass) 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, 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) { agent->next_candidate_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 (); } @@ -224,7 +327,16 @@ nice_agent_get_property ( break; 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: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -248,7 +360,15 @@ nice_agent_set_property ( break; 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; default: @@ -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 nice_agent_add_local_host_candidate ( NiceAgent *agent, @@ -278,6 +425,8 @@ nice_agent_add_local_host_candidate ( candidate->base_addr = *address; component->local_candidates = g_slist_append (component->local_candidates, candidate); + candidate->priority = + 0x1000000 * 126 + 0x100 * 0 + 256 - component_id; /* sect:4.1.2.1(-14) */ /* generate username/password */ nice_rng_generate_bytes_print (agent->rng, 8, candidate->username); @@ -293,6 +442,271 @@ nice_agent_add_local_host_candidate ( 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: @@ -313,27 +727,60 @@ nice_agent_add_stream ( GSList *i; 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->id = agent->next_stream_id++; agent->streams = g_slist_append (agent->streams, stream); /* 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) { NiceAddress *addr = i->data; + CandidateDiscoveryUDP *cand_udp; + int sockfd; nice_agent_add_local_host_candidate (agent, stream->id, stream->component->id, addr); - /* XXX: need to check for redundant candidates? */ - /* later: send STUN requests to obtain server-reflexive candidates */ + if (agent->full_mode) { + 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; } - /** * nice_agent_remove_stream: * @agent: a NiceAgent @@ -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 * @agent: a NiceAgent @@ -406,27 +945,55 @@ nice_agent_add_remote_candidate ( const gchar *username, const gchar *password) { - NiceCandidate *candidate; - Component *component; - - 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; - /* XXX: do remote candidates need IDs? */ - candidate->id = 0; - candidate->addr = *addr; - strncpy (candidate->username, username, sizeof (candidate->username)); - strncpy (candidate->password, password, sizeof (candidate->password)); - - component->remote_candidates = g_slist_append (component->remote_candidates, - candidate); - - /* later: for each component, generate a new check with the new candidate */ + priv_add_remote_candidate (agent, + stream_id, + component_id, + type, + addr, + NULL, + NICE_CANDIDATE_TRANSPORT_UDP, + 0, + username, + password, + NULL); + + /* 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 static NiceCandidate * @@ -505,6 +1072,8 @@ _handle_stun_binding_request ( * --> send error */ + /* XXX-KV: update to use Remi's implementation */ + attr = stun_message_find_attribute (msg, STUN_ATTRIBUTE_USERNAME); if (attr == NULL) @@ -542,8 +1111,8 @@ _handle_stun_binding_request ( #if 0 /* usernames match; check address */ - if (rtmp->addr.addr_ipv4 == ntohs (from.sin_addr.s_addr) && - rtmp->port == ntohl (from.sin_port)) + if (rtmp->addr.addr_ipv4 == ntohl (from.sin_addr.s_addr) && + rtmp->port == ntohs (from.sin_port)) { /* this is a candidate we know about, just send a reply */ /* is candidate pair active now? */ @@ -586,6 +1155,8 @@ RESPOND: guint len; gchar *packed; + /* XXX-KV: update to use Remi's implementation */ + response = stun_message_new (STUN_MESSAGE_BINDING_RESPONSE, msg->transaction_id, 2); response->attributes[0] = stun_attribute_mapped_address_new ( @@ -607,6 +1178,8 @@ RESPOND: guint len; gchar *packed; + /* XXX-KV: update to use Remi's implementation */ + extra = stun_message_new (STUN_MESSAGE_BINDING_REQUEST, NULL, 1); @@ -657,6 +1230,8 @@ ERROR: guint len; gchar *packed; + /* XXX-KV: update to use Remi's implementation */ + response = stun_message_new (STUN_MESSAGE_BINDING_ERROR_RESPONSE, msg->transaction_id, 0); len = stun_message_pack (response, &packed); @@ -763,6 +1338,8 @@ _nice_agent_recv ( /* connectivity checks are described in ICE-13 ยง7. */ StunMessage *msg; + /* XXX-KV: update to use Remi's implementation */ + msg = stun_message_unpack (len, buf); if (msg != NULL) @@ -1052,6 +1629,9 @@ nice_agent_get_remote_candidates ( if (!find_component (agent, stream_id, component_id, NULL, &component)) 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); } @@ -1062,6 +1642,12 @@ nice_agent_dispose (GObject *object) GSList *i; 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) { NiceAddress *a = i->data; @@ -1082,8 +1668,8 @@ nice_agent_dispose (GObject *object) g_slist_free (agent->streams); agent->streams = NULL; - g_free (agent->stun_server); - agent->stun_server = NULL; + g_free (agent->stun_server_ip); + agent->stun_server_ip = NULL; nice_rng_free (agent->rng); agent->rng = NULL; @@ -1200,4 +1786,3 @@ nice_agent_main_context_attach ( agent->read_func_data = data; return TRUE; } - diff --git a/agent/agent.h b/agent/agent.h index d211322..61893f7 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -71,11 +71,34 @@ G_BEGIN_DECLS typedef enum { - NICE_COMPONENT_STATE_DISCONNECTED, - NICE_COMPONENT_STATE_CONNECTING, - NICE_COMPONENT_STATE_CONNECTED, + NICE_COMPONENT_STATE_DISCONNECTED, /* no activity scheduled */ + NICE_COMPONENT_STATE_GATHERING, /* gathering local candidates */ + 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; +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 void (*NiceAgentRecvFunc) ( @@ -87,6 +110,7 @@ struct _NiceAgent GObject parent; guint next_candidate_id; guint next_stream_id; + gboolean full_mode; NiceUDPSocketFactory *socket_factory; GSList *local_addresses; GSList *streams; @@ -94,7 +118,14 @@ struct _NiceAgent GMainContext *main_context; NiceAgentRecvFunc read_func; 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; }; @@ -133,6 +164,13 @@ nice_agent_add_remote_candidate ( const gchar *username, const gchar *password); +void +nice_agent_set_remote_candidates ( + NiceAgent *agent, + guint stream_id, + guint component_id, + GSList *candidates); + guint nice_agent_recv ( NiceAgent *agent, diff --git a/agent/candidate.c b/agent/candidate.c index b607e88..ab80e21 100644 --- a/agent/candidate.c +++ b/agent/candidate.c @@ -65,6 +65,9 @@ nice_candidate_free (NiceCandidate *candidate) if (candidate->source) g_source_destroy (candidate->source); + if (candidate->foundation) + g_free (candidate->foundation); + g_slice_free (NiceCandidate, candidate); } diff --git a/agent/candidate.h b/agent/candidate.h index 736c175..8aaefff 100644 --- a/agent/candidate.h +++ b/agent/candidate.h @@ -50,23 +50,28 @@ typedef enum NICE_CANDIDATE_TYPE_RELAYED, } NiceCandidateType; +typedef enum +{ + NICE_CANDIDATE_TRANSPORT_UDP, +} NiceCandidateTransport; typedef struct _NiceCandidate NiceCandidate; struct _NiceCandidate { NiceCandidateType type; - guint id; + NiceCandidateTransport transport; + guint id; NiceAddress addr; NiceAddress base_addr; guint32 priority; guint stream_id; guint component_id; // guint generation; - // gchar *foundation; + gchar *foundation; /* note: if NULL, derive foundation from 'id' */ NiceUDPSocket sock; - gchar username[128]; - gchar password[128]; + gchar username[128]; /* XXX: why 128 chars? */ + gchar password[128]; /* XXX: why 128 chars? */ GSource *source; }; |