Commit 7d0b3ab4 authored by Olivier Crête's avatar Olivier Crête Committed by Olivier Crête

agent: Move UPnP handling to each stream

Also rewrite the logic a little, and try to make the code a little clearer.
parent 17c6d299
...@@ -166,12 +166,10 @@ struct _NiceAgent ...@@ -166,12 +166,10 @@ struct _NiceAgent
"Determining Role" ID-19) */ "Determining Role" ID-19) */
NiceCompatibility compatibility; /* property: Compatibility mode */ NiceCompatibility compatibility; /* property: Compatibility mode */
gboolean media_after_tick; /* Received media after keepalive tick */ gboolean media_after_tick; /* Received media after keepalive tick */
gboolean upnp_enabled; /* whether UPnP discovery is enabled */
#ifdef HAVE_GUPNP #ifdef HAVE_GUPNP
GUPnPSimpleIgdThread* upnp; /* GUPnP Single IGD agent */ GUPnPSimpleIgdThread* upnp; /* GUPnP Single IGD agent */
gboolean upnp_enabled; /* whether UPnP discovery is enabled */
guint upnp_timeout; /* UPnP discovery timeout */ guint upnp_timeout; /* UPnP discovery timeout */
GSList *upnp_mapping; /* NiceAddresses of cands being mapped */
GSource *upnp_timer_source; /* source of upnp timeout timer */
#endif #endif
gchar *software_attribute; /* SOFTWARE attribute */ gchar *software_attribute; /* SOFTWARE attribute */
gboolean reliable; /* property: reliable */ gboolean reliable; /* property: reliable */
...@@ -246,7 +244,7 @@ StunUsageIceCompatibility agent_to_ice_compatibility (NiceAgent *agent); ...@@ -246,7 +244,7 @@ StunUsageIceCompatibility agent_to_ice_compatibility (NiceAgent *agent);
StunUsageTurnCompatibility agent_to_turn_compatibility (NiceAgent *agent); StunUsageTurnCompatibility agent_to_turn_compatibility (NiceAgent *agent);
NiceTurnSocketCompatibility agent_to_turn_socket_compatibility (NiceAgent *agent); NiceTurnSocketCompatibility agent_to_turn_socket_compatibility (NiceAgent *agent);
void agent_remove_local_candidate (NiceAgent *agent, void agent_remove_local_candidate (NiceAgent *agent, NiceStream *stream,
NiceCandidate *candidate); NiceCandidate *candidate);
void nice_agent_init_stun_agent (NiceAgent *agent, StunAgent *stun_agent); void nice_agent_init_stun_agent (NiceAgent *agent, StunAgent *stun_agent);
......
...@@ -145,8 +145,6 @@ enum ...@@ -145,8 +145,6 @@ enum
static guint signals[N_SIGNALS]; static guint signals[N_SIGNALS];
static void priv_stop_upnp (NiceAgent *agent);
static void pseudo_tcp_socket_opened (PseudoTcpSocket *sock, gpointer user_data); static void pseudo_tcp_socket_opened (PseudoTcpSocket *sock, gpointer user_data);
static void pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data); static void pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data);
static void pseudo_tcp_socket_writable (PseudoTcpSocket *sock, gpointer user_data); static void pseudo_tcp_socket_writable (PseudoTcpSocket *sock, gpointer user_data);
...@@ -1630,9 +1628,7 @@ nice_agent_set_property ( ...@@ -1630,9 +1628,7 @@ nice_agent_set_property (
break; break;
case PROP_UPNP: case PROP_UPNP:
#ifdef HAVE_GUPNP
agent->upnp_enabled = g_value_get_boolean (value); agent->upnp_enabled = g_value_get_boolean (value);
#endif
break; break;
case PROP_RELIABLE: case PROP_RELIABLE:
...@@ -2218,7 +2214,7 @@ _transport_to_string (NiceCandidateTransport type) { ...@@ -2218,7 +2214,7 @@ _transport_to_string (NiceCandidateTransport type) {
void agent_gathering_done (NiceAgent *agent) void agent_gathering_done (NiceAgent *agent)
{ {
gboolean upnp_running = FALSE;
GSList *i, *j, *k, *l, *m; GSList *i, *j, *k, *l, *m;
for (i = agent->streams; i; i = i->next) { for (i = agent->streams; i; i = i->next) {
...@@ -2234,6 +2230,11 @@ void agent_gathering_done (NiceAgent *agent) ...@@ -2234,6 +2230,11 @@ void agent_gathering_done (NiceAgent *agent)
if (!stream->gathering) if (!stream->gathering)
continue; continue;
#ifdef HAVE_GUPNP
if (stream->upnp_timer_source != NULL)
upnp_running = TRUE;
#endif
for (j = stream->components; j; j = j->next) { for (j = stream->components; j; j = j->next) {
NiceComponent *component = j->data; NiceComponent *component = j->data;
...@@ -2280,7 +2281,7 @@ void agent_gathering_done (NiceAgent *agent) ...@@ -2280,7 +2281,7 @@ void agent_gathering_done (NiceAgent *agent)
"for OC2007R2 compatibility", agent); "for OC2007R2 compatibility", agent);
component->local_candidates = component->local_candidates =
g_slist_remove (component->local_candidates, local_candidate); g_slist_remove (component->local_candidates, local_candidate);
agent_remove_local_candidate (agent, local_candidate); agent_remove_local_candidate (agent, stream, local_candidate);
nice_candidate_free (local_candidate); nice_candidate_free (local_candidate);
goto next_cand; goto next_cand;
} }
...@@ -2305,15 +2306,8 @@ next_cand: ...@@ -2305,15 +2306,8 @@ next_cand:
} }
} }
#ifdef HAVE_GUPNP if (agent->discovery_timer_source == NULL && !upnp_running)
if (agent->discovery_timer_source == NULL &&
agent->upnp_timer_source == NULL) {
agent_signal_gathering_done (agent);
}
#else
if (agent->discovery_timer_source == NULL)
agent_signal_gathering_done (agent); agent_signal_gathering_done (agent);
#endif
} }
void agent_signal_gathering_done (NiceAgent *agent) void agent_signal_gathering_done (NiceAgent *agent)
...@@ -2908,23 +2902,6 @@ nice_agent_set_relay_info(NiceAgent *agent, ...@@ -2908,23 +2902,6 @@ nice_agent_set_relay_info(NiceAgent *agent,
#ifdef HAVE_GUPNP #ifdef HAVE_GUPNP
static void agent_check_upnp_gathering_done (NiceAgent *agent);
static gboolean priv_upnp_timeout_cb_agent_locked (NiceAgent *agent,
gpointer user_data)
{
nice_debug ("Agent %p : UPnP port mapping timed out", agent);
/* We cannot free priv->upnp here as it may be holding mappings open which
* we are using (e.g. if some mappings were successful and others errored). */
g_slist_free_full (agent->upnp_mapping, (GDestroyNotify) nice_address_free);
agent->upnp_mapping = NULL;
agent_check_upnp_gathering_done (agent);
return FALSE;
}
/* Check whether UPnP gathering is done, which is true when the list of pending /* Check whether UPnP gathering is done, which is true when the list of pending
* mappings (upnp_mapping) is empty. When it is empty, we have heard back from * mappings (upnp_mapping) is empty. When it is empty, we have heard back from
* gupnp-igd about each of the mappings we added, either successfully or not. * gupnp-igd about each of the mappings we added, either successfully or not.
...@@ -2932,88 +2909,139 @@ static gboolean priv_upnp_timeout_cb_agent_locked (NiceAgent *agent, ...@@ -2932,88 +2909,139 @@ static gboolean priv_upnp_timeout_cb_agent_locked (NiceAgent *agent,
* Note that upnp_mapping has to be a list, rather than a counter, as the * Note that upnp_mapping has to be a list, rather than a counter, as the
* mapped-external-port and error-mapping-port signals could be emitted multiple * mapped-external-port and error-mapping-port signals could be emitted multiple
* times for each mapping. */ * times for each mapping. */
static void agent_check_upnp_gathering_done (NiceAgent *agent) static void check_upnp_gathering_done (NiceAgent *agent,
NiceStream *stream)
{ {
if (agent->upnp_mapping != NULL) if (stream->upnp_mapping != NULL)
return; return;
if (agent->upnp_timer_source != NULL) { if (stream->upnp_timer_source != NULL) {
g_source_destroy (agent->upnp_timer_source); g_source_destroy (stream->upnp_timer_source);
g_source_unref (agent->upnp_timer_source); g_source_unref (stream->upnp_timer_source);
agent->upnp_timer_source = NULL; stream->upnp_timer_source = NULL;
} }
agent_gathering_done (agent); agent_gathering_done (agent);
} }
static void _upnp_mapped_external_port (GUPnPSimpleIgd *self, gchar *proto, static gboolean priv_upnp_timeout_cb_agent_locked (NiceAgent *agent,
gchar *external_ip, gchar *replaces_external_ip, guint external_port, gpointer user_data)
gchar *local_ip, guint local_port, gchar *description, gpointer user_data)
{ {
NiceAgent *agent = (NiceAgent*)user_data; NiceStream *stream = user_data;
NiceAddress localaddr;
NiceAddress externaddr;
NiceCandidateTransport transport;
GSList *i, *j, *k;
agent_lock (agent); nice_debug ("Agent %p s:%d : UPnP port mapping timed out", agent,
stream->id);
if (agent->upnp_timer_source == NULL) /* Force it to be done */
goto end; stream->upnp_mapped = g_slist_concat (stream->upnp_mapped,
stream->upnp_mapping);
stream->upnp_mapping = NULL;
nice_debug ("Agent %p : Successfully mapped %s:%d to %s:%d", agent, local_ip, check_upnp_gathering_done (agent, stream);
local_port, external_ip, external_port);
if (!nice_address_set_from_string (&localaddr, local_ip)) return G_SOURCE_REMOVE;
goto end; }
nice_address_set_port (&localaddr, local_port);
static GSList *
priv_find_upnp_candidate (GSList *upnp_list, NiceCandidate *host_candidate)
{
GSList *item;
for (item = upnp_list; item; item = item->next) {
NiceCandidate *c = item->data;
if (!nice_candidate_equal_target (host_candidate, c))
continue;
if (g_strcmp0 (proto, "TCP") == 0) if ((host_candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP) !=
transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE; (c->transport == NICE_CANDIDATE_TRANSPORT_UDP))
continue;
return item;
}
return NULL;
}
static NiceStream *
priv_find_candidate_for_upnp_mapping (NiceAgent *agent, gchar *proto,
gchar *local_ip, guint local_port, gboolean only_mapping,
gboolean *was_mapping, GSList **item)
{
GSList *i;
NiceCandidate upnp_candidate = { .type = NICE_CANDIDATE_TYPE_HOST };
if (!nice_address_set_from_string (&upnp_candidate.addr, local_ip))
return NULL;
nice_address_set_port (&upnp_candidate.addr, local_port);
if (!g_strcmp0 (proto, "UDP"))
upnp_candidate.transport = NICE_CANDIDATE_TRANSPORT_UDP;
else else
transport = NICE_CANDIDATE_TRANSPORT_UDP; upnp_candidate.transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
for (i = agent->upnp_mapping; i; i = i->next) { for (i = agent->streams; i; i = i->next) {
NiceAddress *addr = i->data; NiceStream *stream = i->data;
if (nice_address_equal (&localaddr, addr)) { GSList *j;
agent->upnp_mapping = g_slist_remove (agent->upnp_mapping, addr);
nice_address_free (addr); j = priv_find_upnp_candidate (stream->upnp_mapping, &upnp_candidate);
break; if (was_mapping)
*was_mapping = (j != NULL);
if (j == NULL && !only_mapping)
j = priv_find_upnp_candidate (stream->upnp_mapped, &upnp_candidate);
if (j) {
*item = j;
return stream;
} }
} }
return NULL;
}
static void _upnp_mapped_external_port (GUPnPSimpleIgd *self, gchar *proto,
gchar *external_ip, gchar *replaces_external_ip, guint external_port,
gchar *local_ip, guint local_port, gchar *description, gpointer user_data)
{
NiceAgent *agent = (NiceAgent*)user_data;
NiceStream *stream = NULL;
GSList *item;
gboolean was_mapping = FALSE;
NiceAddress externaddr;
nice_debug ("Agent %p : Successfully mapped %s:%d to %s:%d", agent, local_ip,
local_port, external_ip, external_port);
if (!nice_address_set_from_string (&externaddr, external_ip)) if (!nice_address_set_from_string (&externaddr, external_ip))
goto end; return;
nice_address_set_port (&externaddr, external_port); nice_address_set_port (&externaddr, external_port);
for (i = agent->streams; i; i = i->next) { agent_lock (agent);
NiceStream *stream = i->data;
for (j = stream->components; j; j = j->next) {
NiceComponent *component = j->data;
for (k = component->local_candidates; k; k = k->next) {
NiceCandidateImpl *local_candidate = k->data;
if (agent->force_relay && stream = priv_find_candidate_for_upnp_mapping (agent, proto,
local_candidate->c.type != NICE_CANDIDATE_TYPE_RELAYED) local_ip, local_port, FALSE, &was_mapping, &item);
continue;
if (nice_address_equal (&localaddr, &local_candidate->c.base_addr)) { if (stream && stream->upnp_timer_source) {
discovery_add_server_reflexive_candidate ( NiceCandidateImpl *host_candidate = item->data;
agent,
stream->id, if (was_mapping) {
component->id, stream->upnp_mapping = g_slist_delete_link (stream->upnp_mapping, item);
&externaddr, stream->upnp_mapped = g_slist_prepend (stream->upnp_mapped,
transport, host_candidate);
local_candidate->sockptr,
TRUE);
goto end;
}
}
} }
}
end: discovery_add_server_reflexive_candidate (agent,
agent_check_upnp_gathering_done (agent); host_candidate->c.stream_id, host_candidate->c.component_id,
&externaddr,
host_candidate->c.transport,
host_candidate->sockptr,
TRUE);
check_upnp_gathering_done (agent, stream);
}
agent_unlock_and_emit (agent); agent_unlock_and_emit (agent);
} }
...@@ -3022,32 +3050,180 @@ static void _upnp_error_mapping_port (GUPnPSimpleIgd *self, GError *error, ...@@ -3022,32 +3050,180 @@ static void _upnp_error_mapping_port (GUPnPSimpleIgd *self, GError *error,
gchar *proto, guint external_port, gchar *local_ip, guint local_port, gchar *proto, guint external_port, gchar *local_ip, guint local_port,
gchar *description, gpointer user_data) gchar *description, gpointer user_data)
{ {
NiceAgent *agent = (NiceAgent*)user_data; NiceAgent *agent = (NiceAgent *) user_data;
NiceAddress localaddr; NiceStream *stream;
GSList *i; GSList *item;
agent_lock (agent); agent_lock (agent);
nice_debug ("Agent %p : Error mapping %s:%d to %d (%d) : %s", agent, local_ip, nice_debug ("Agent %p : Error mapping %s:%d to %d (%d) : %s", agent, local_ip,
local_port, external_port, error->domain, error->message); local_port, external_port, error->domain, error->message);
if (nice_address_set_from_string (&localaddr, local_ip)) {
nice_address_set_port (&localaddr, local_port);
for (i = agent->upnp_mapping; i; i = i->next) { stream = priv_find_candidate_for_upnp_mapping (agent, proto,
NiceAddress *addr = i->data; local_ip, local_port, TRUE, NULL, &item);
if (nice_address_equal (&localaddr, addr)) {
agent->upnp_mapping = g_slist_remove (agent->upnp_mapping, addr);
nice_address_free (addr);
break;
}
}
agent_check_upnp_gathering_done (agent); if (stream) {
NiceCandidate *host_candidate = item->data;
stream->upnp_mapping = g_slist_delete_link (stream->upnp_mapping, item);
stream->upnp_mapped =
g_slist_prepend (stream->upnp_mapped, host_candidate);
check_upnp_gathering_done (agent, stream);
} }
agent_unlock_and_emit (agent); agent_unlock_and_emit (agent);
} }
static void
priv_add_upnp_discovery (NiceAgent *agent, NiceStream *stream,
NiceCandidate *host_candidate)
{
gchar local_ip[NICE_ADDRESS_STRING_LEN];
if (!agent->upnp_enabled || agent->force_relay)
return;
if (agent->upnp == NULL) {
agent->upnp = gupnp_simple_igd_thread_new ();
if (agent->upnp == NULL) {
nice_debug ("Agent %p : Could not initialize GUPnP library", agent);
agent->upnp_enabled = FALSE;
return;
}
g_signal_connect (agent->upnp, "mapped-external-port",
G_CALLBACK (_upnp_mapped_external_port), agent);
g_signal_connect (agent->upnp, "error-mapping-port",
G_CALLBACK (_upnp_error_mapping_port), agent);
}
if (host_candidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE)
return;
if (priv_find_upnp_candidate (stream->upnp_mapping, host_candidate))
return;
if (priv_find_upnp_candidate (stream->upnp_mapped, host_candidate))
return;
nice_address_to_string (&host_candidate->addr, local_ip);
gupnp_simple_igd_add_port (GUPNP_SIMPLE_IGD (agent->upnp),
host_candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "UDP" : "TCP",
0, local_ip, nice_address_get_port (&host_candidate->addr),
0, PACKAGE_STRING);
stream->upnp_mapping = g_slist_prepend (stream->upnp_mapping,
nice_candidate_copy (host_candidate));
if (stream->upnp_timer_source == NULL)
agent_timeout_add_with_context (agent, &stream->upnp_timer_source,
"UPnP timeout", agent->upnp_timeout,
priv_upnp_timeout_cb_agent_locked, stream);
}
static void
priv_remove_upnp_mapping (NiceAgent *agent, NiceCandidate *host_candidate)
{
gchar local_ip[NICE_ADDRESS_STRING_LEN] = "";
nice_address_to_string (&host_candidate->addr, local_ip);
g_print ("REMOVING %s: %d\n", local_ip, nice_address_get_port (&host_candidate->addr));
gupnp_simple_igd_remove_port_local (GUPNP_SIMPLE_IGD (agent->upnp),
host_candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "UDP" :
"TCP",
local_ip, nice_address_get_port (&host_candidate->addr));
}
void
agent_remove_local_candidate (NiceAgent *agent, NiceStream *stream,
NiceCandidate *local_candidate)
{
GSList *item;
if (agent->upnp == NULL)
return;
if (local_candidate->type != NICE_CANDIDATE_TYPE_HOST)
return;
if (local_candidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE)
return;
item = priv_find_upnp_candidate (stream->upnp_mapping, local_candidate);
if (item) {
nice_candidate_free (item->data);
stream->upnp_mapping = g_slist_delete_link (stream->upnp_mapping, item);
}
item = priv_find_upnp_candidate (stream->upnp_mapped, local_candidate);
if (item) {
nice_candidate_free (item->data);
stream->upnp_mapped = g_slist_delete_link (stream->upnp_mapped, item);
}
priv_remove_upnp_mapping (agent, local_candidate);
}
static void
priv_stop_upnp (NiceAgent *agent, NiceStream *stream)
{
if (agent->upnp == NULL)
return;
if (stream->upnp_timer_source != NULL) {
g_source_destroy (stream->upnp_timer_source);
g_source_unref (stream->upnp_timer_source);
stream->upnp_timer_source = NULL;
}
while (stream->upnp_mapping) {
NiceCandidate *host_candidate = stream->upnp_mapping->data;
priv_remove_upnp_mapping (agent, host_candidate);
nice_candidate_free (host_candidate);
stream->upnp_mapping = g_slist_delete_link (stream->upnp_mapping,
stream->upnp_mapping);
}
while (stream->upnp_mapped) {
NiceCandidate *host_candidate = stream->upnp_mapped->data;
priv_remove_upnp_mapping (agent, host_candidate);
nice_candidate_free (host_candidate);
stream->upnp_mapped = g_slist_delete_link (stream->upnp_mapped,
stream->upnp_mapped);
}
}
#else /* HAVE_GUPNP */
static inline void
priv_add_upnp_discovery (NiceAgent *agent, NiceStream *stream,
NiceCandidate *host_candidate)
{
/* Use the upnp_enabled to print this only once */
if (agent->upnp_enabled) {
nice_debug ("Agent %p : libnice compiled without GUPnP support", agent);
agent->upnp_enabled = FALSE;
}
}
static void
priv_stop_upnp (NiceAgent *agent, NiceStream *stream) {
/* Do nothing */
}
void
agent_remove_local_candidate (NiceAgent *agent, NiceStream *stream,
NiceCandidate *local_candidate)
{
/* Do nothing */
}
#endif #endif
NICEAPI_EXPORT gboolean NICEAPI_EXPORT gboolean
...@@ -3082,25 +3258,6 @@ nice_agent_gather_candidates ( ...@@ -3082,25 +3258,6 @@ nice_agent_gather_candidates (
nice_debug ("Agent %p : In %s mode, starting candidate gathering.", agent, nice_debug ("Agent %p : In %s mode, starting candidate gathering.", agent,
agent->full_mode ? "ICE-FULL" : "ICE-LITE"); agent->full_mode ? "ICE-FULL" : "ICE-LITE");
#ifdef HAVE_GUPNP
if (agent->upnp_enabled && agent->upnp == NULL && !agent->force_relay) {
agent->upnp = gupnp_simple_igd_thread_new ();
if (agent->upnp) {
g_signal_connect (agent->upnp, "mapped-external-port",
G_CALLBACK (_upnp_mapped_external_port), agent);
g_signal_connect (agent->upnp, "error-mapping-port",
G_CALLBACK (_upnp_error_mapping_port), agent);
} else {
nice_debug ("Agent %p : Error creating UPnP Simple IGD agent", agent);
}
} else {
nice_debug ("Agent %p : UPnP property Disabled", agent);
}
#else
nice_debug ("Agent %p : libnice compiled without UPnP support", agent);
#endif
/* if no local addresses added, generate them ourselves */ /* if no local addresses added, generate them ourselves */
if (agent->local_addresses == NULL) { if (agent->local_addresses == NULL) {
GList *addresses = nice_interfaces_get_local_ips (FALSE); GList *addresses = nice_interfaces_get_local_ips (FALSE);
...@@ -3156,11 +3313,6 @@ nice_agent_gather_candidates ( ...@@ -3156,11 +3313,6 @@ nice_agent_gather_candidates (
NiceAddress *addr = i->data; NiceAddress *addr = i->data;
NiceCandidateImpl *host_candidate; NiceCandidateImpl *host_candidate;
#ifdef HAVE_GUPNP
gchar local_ip[NICE_ADDRESS_STRING_LEN];
nice_address_to_string (addr, local_ip);
#endif
for (add_type = ADD_HOST_MIN; add_type <= ADD_HOST_MAX; add_type++) { for (add_type = ADD_HOST_MIN; add_type <= ADD_HOST_MAX; add_type++) {
NiceCandidateTransport transport; NiceCandidateTransport transport;
guint current_port; guint current_port;
...@@ -3252,23 +3404,7 @@ nice_agent_gather_candidates ( ...@@ -3252,23 +3404,7 @@ nice_agent_gather_candidates (
nice_socket_set_writable_callback (host_candidate->sockptr, nice_socket_set_writable_callback (host_candidate->sockptr,
_tcp_sock_is_writable, component); _tcp_sock_is_writable, component);
#ifdef HAVE_GUPNP priv_add_upnp_discovery (agent, stream, (NiceCandidate *) host_candidate);
if (agent->upnp_enabled && agent->upnp &&
transport != NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) {
NiceAddress *base_addr = nice_address_dup (&host_candidate->c.base_addr);
nice_debug ("Agent %p: Adding UPnP port %s:%d", agent, local_ip,
nice_address_get_port (base_addr));
gupnp_simple_igd_add_port (GUPNP_SIMPLE_IGD (agent->upnp),
transport == NICE_CANDIDATE_TRANSPORT_UDP ? "UDP" : "TCP",
0, local_ip, nice_address_get_port (base_addr),
0, PACKAGE_STRING);
agent->upnp_mapping = g_slist_prepend (agent->upnp_mapping, base_addr);
agent_timeout_add_with_context (agent, &agent->upnp_timer_source,
"UPnP timeout", agent->upnp_timeout,
priv_upnp_timeout_cb_agent_locked, agent);
}
#endif
/* TODO: Add server-reflexive support for TCP candidates */ /* TODO: Add server-reflexive support for TCP candidates */
if (agent->full_mode && agent->stun_server_ip && !agent->force_relay && if (agent->full_mode && agent->stun_server_ip && !agent->force_relay &&
...@@ -3338,7 +3474,7 @@ nice_agent_gather_candidates ( ...@@ -3338,7 +3474,7 @@ nice_agent_gather_candidates (
/* note: no async discoveries pending, signal that we are ready */ /* note: no async discoveries pending, signal that we are ready */
if (agent->discovery_unsched_items == 0 && if (agent->discovery_unsched_items == 0 &&
#ifdef HAVE_GUPNP #ifdef HAVE_GUPNP
agent->upnp_mapping == NULL) { stream->upnp_mapping == NULL) {
#else #else
TRUE) { TRUE) {
#endif #endif
...@@ -3355,20 +3491,14 @@ nice_agent_gather_candidates ( ...@@ -3355,20 +3491,14 @@ nice_agent_gather_candidates (
g_slist_free (local_addresses); g_slist_free (local_addresses);
if (ret == FALSE) { if (ret == FALSE) {
priv_stop_upnp (agent); priv_stop_upnp (agent, stream);
for (cid = 1; cid <= stream->n_components; cid++) { for (cid = 1; cid <= stream->n_components; cid++) {
NiceComponent *component = nice_stream_find_component_by_id (stream, cid); NiceComponent *component = nice_stream_find_component_by_id (stream, cid);
nice_component_free_socket_sources (component); nice_component_free_socket_sources (component);
for (i = component->local_candidates; i; i = i->next) { g_slist_free_full (component->local_candidates,
NiceCandidate *candidate = i->data; (GDestroyNotify) nice_candidate_free);
agent_remove_local_candidate (agent, candidate);
nice_candidate_free (candidate);
}
g_slist_free (component->local_candidates);
component->local_candidates = NULL; component->local_candidates = NULL;
} }
discovery_prune_stream (agent, stream_id); discovery_prune_stream (agent, stream_id);
...@@ -3379,44 +3509,6 @@ nice_agent_gather_candidates ( ...@@ -3379,44 +3509,6 @@ nice_agent_gather_candidates (
return ret; return ret;
} }
void agent_remove_local_candidate (NiceAgent *agent, NiceCandidate *candidate)
{
#ifdef HAVE_GUPNP
gchar local_ip[NICE_ADDRESS_STRING_LEN];
if (agent->upnp == NULL)
return;
if (candidate->type != NICE_CANDIDATE_TYPE_HOST)
return;
if (nice_address_get_port (&candidate->addr) == 0)
return;
nice_address_to_string (&candidate->addr, local_ip);
gupnp_simple_igd_remove_port_local (GUPNP_SIMPLE_IGD (agent->upnp), "UDP",
local_ip, nice_address_get_port (&candidate->addr));
#endif
}
static void priv_stop_upnp (NiceAgent *agent)
{
#ifdef HAVE_GUPNP
if (!agent->upnp)
return;
g_slist_free_full (agent->upnp_mapping, (GDestroyNotify) nice_address_free);
agent->upnp_mapping = NULL;
if (agent->upnp_timer_source != NULL) {
g_source_destroy (agent->upnp_timer_source);
g_source_unref (agent->upnp_timer_source);
agent->upnp_timer_source = NULL;
}
#endif
}
static void priv_remove_keepalive_timer (NiceAgent *agent) static void priv_remove_keepalive_timer (NiceAgent *agent)
{ {
if (agent->keepalive_timer_source != NULL) { if (agent->keepalive_timer_source != NULL) {
...@@ -3469,6 +3561,8 @@ nice_agent_remove_stream ( ...@@ -3469,6 +3561,8 @@ nice_agent_remove_stream (
return; return;
} }
priv_stop_upnp (agent, stream);
/* note: remove items with matching stream_ids from both lists */ /* note: remove items with matching stream_ids from both lists */
conn_check_prune_stream (agent, stream); conn_check_prune_stream (agent, stream);
discovery_prune_stream (agent, stream_id); discovery_prune_stream (agent, stream_id);
...@@ -5458,6 +5552,7 @@ nice_agent_dispose (GObject *object) ...@@ -5458,6 +5552,7 @@ nice_agent_dispose (GObject *object)
while (agent->streams) { while (agent->streams) {
NiceStream *s = agent->streams->data; NiceStream *s = agent->streams->data;
priv_stop_upnp (agent, s);
nice_stream_close (agent, s); nice_stream_close (agent, s);
g_object_unref (s); g_object_unref (s);
...@@ -5491,8 +5586,6 @@ nice_agent_dispose (GObject *object) ...@@ -5491,8 +5586,6 @@ nice_agent_dispose (GObject *object)
nice_rng_free (agent->rng); nice_rng_free (agent->rng);
agent->rng = NULL; agent->rng = NULL;
priv_stop_upnp (agent);
#ifdef HAVE_GUPNP #ifdef HAVE_GUPNP
if (agent->upnp) { if (agent->upnp) {
g_object_unref (agent->upnp); g_object_unref (agent->upnp);
......
...@@ -197,8 +197,8 @@ nice_component_remove_socket (NiceAgent *agent, NiceComponent *cmp, ...@@ -197,8 +197,8 @@ nice_component_remove_socket (NiceAgent *agent, NiceComponent *cmp,
conn_check_prune_socket (agent, stream, cmp, candidate->sockptr); conn_check_prune_socket (agent, stream, cmp, candidate->sockptr);
nice_component_detach_socket (cmp, candidate->sockptr); nice_component_detach_socket (cmp, candidate->sockptr);
} }
agent_remove_local_candidate (agent, (NiceCandidate *) candidate); agent_remove_local_candidate (agent, stream, (NiceCandidate *) candidate);
nice_candidate_free ((NiceCandidate *) candidate); nice_candidate_free ((NiceCandidate *)candidate);
cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, i); cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, i);
i = next; i = next;
...@@ -289,7 +289,7 @@ nice_component_clean_turn_servers (NiceAgent *agent, NiceComponent *cmp) ...@@ -289,7 +289,7 @@ nice_component_clean_turn_servers (NiceAgent *agent, NiceComponent *cmp)
cmp->selected_pair.priority = 0; cmp->selected_pair.priority = 0;
cmp->turn_candidate = candidate; cmp->turn_candidate = candidate;
} else { } else {
agent_remove_local_candidate (agent, (NiceCandidate *) candidate); agent_remove_local_candidate (agent, stream, (NiceCandidate *) candidate);
relay_candidates = g_slist_append(relay_candidates, candidate); relay_candidates = g_slist_append(relay_candidates, candidate);
} }
cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, i); cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, i);
...@@ -324,7 +324,7 @@ nice_component_clear_selected_pair (NiceComponent *component) ...@@ -324,7 +324,7 @@ nice_component_clear_selected_pair (NiceComponent *component)
/* Must be called with the agent lock held as it touches internal Component /* Must be called with the agent lock held as it touches internal Component
* state. */ * state. */
void void
nice_component_close (NiceAgent *agent, NiceComponent *cmp) nice_component_close (NiceAgent *agent, NiceStream *stream, NiceComponent *cmp)
{ {
IOCallbackData *data; IOCallbackData *data;
GOutputVector *vec; GOutputVector *vec;
...@@ -353,7 +353,7 @@ nice_component_close (NiceAgent *agent, NiceComponent *cmp) ...@@ -353,7 +353,7 @@ nice_component_close (NiceAgent *agent, NiceComponent *cmp)
cmp->turn_candidate = NULL; cmp->turn_candidate = NULL;
while (cmp->local_candidates) { while (cmp->local_candidates) {
agent_remove_local_candidate (agent, cmp->local_candidates->data); agent_remove_local_candidate (agent, stream, cmp->local_candidates->data);
nice_candidate_free (cmp->local_candidates->data); nice_candidate_free (cmp->local_candidates->data);
cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, cmp->local_candidates = g_slist_delete_link (cmp->local_candidates,
cmp->local_candidates); cmp->local_candidates);
......
...@@ -236,7 +236,8 @@ NiceComponent * ...@@ -236,7 +236,8 @@ NiceComponent *
nice_component_new (guint component_id, NiceAgent *agent, NiceStream *stream); nice_component_new (guint component_id, NiceAgent *agent, NiceStream *stream);
void void
nice_component_close (NiceAgent *agent, NiceComponent *component); nice_component_close (NiceAgent *agent, NiceStream *stream,
NiceComponent *component);
gboolean gboolean
nice_component_find_pair (NiceComponent *component, NiceAgent *agent, nice_component_find_pair (NiceComponent *component, NiceAgent *agent,
......
...@@ -89,7 +89,7 @@ nice_stream_close (NiceAgent *agent, NiceStream *stream) ...@@ -89,7 +89,7 @@ nice_stream_close (NiceAgent *agent, NiceStream *stream)
for (i = stream->components; i; i = i->next) { for (i = stream->components; i; i = i->next) {
NiceComponent *component = i->data; NiceComponent *component = i->data;
nice_component_close (agent, component); nice_component_close (agent, stream, component);
} }
} }
......
...@@ -90,6 +90,12 @@ struct _NiceStream { ...@@ -90,6 +90,12 @@ struct _NiceStream {
gboolean peer_gathering_done; gboolean peer_gathering_done;
gint tos; gint tos;
guint tick_counter; guint tick_counter;
#ifdef HAVE_GUPNP
GSList *upnp_mapping; /* NiceCandidate being mapped */
GSList *upnp_mapped; /* NiceCandidate mapped with UPnP */
GSource *upnp_timer_source; /* source of upnp timeout timer */
#endif
}; };
typedef struct { typedef struct {
......
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