summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier CrĂȘte <olivier.crete@collabora.com>2020-08-18 16:04:58 -0400
committerOlivier CrĂȘte <olivier.crete@ocrete.ca>2020-10-21 01:24:39 +0000
commit7d0b3ab421f99467404bfc1b90c6049670264b22 (patch)
tree74ffc8a223fc1bd9216b0aa59207a272a6b2ae05
parent17c6d299c093347e35f2c981ec8107954308193a (diff)
downloadlibnice-7d0b3ab421f99467404bfc1b90c6049670264b22.tar.gz
agent: Move UPnP handling to each stream
Also rewrite the logic a little, and try to make the code a little clearer.
-rw-r--r--agent/agent-priv.h6
-rw-r--r--agent/agent.c477
-rw-r--r--agent/component.c10
-rw-r--r--agent/component.h3
-rw-r--r--agent/stream.c2
-rw-r--r--agent/stream.h6
6 files changed, 301 insertions, 203 deletions
diff --git a/agent/agent-priv.h b/agent/agent-priv.h
index d6c488c..8c08b28 100644
--- a/agent/agent-priv.h
+++ b/agent/agent-priv.h
@@ -166,12 +166,10 @@ struct _NiceAgent
"Determining Role" ID-19) */
NiceCompatibility compatibility; /* property: Compatibility mode */
gboolean media_after_tick; /* Received media after keepalive tick */
+ gboolean upnp_enabled; /* whether UPnP discovery is enabled */
#ifdef HAVE_GUPNP
GUPnPSimpleIgdThread* upnp; /* GUPnP Single IGD agent */
- gboolean upnp_enabled; /* whether UPnP discovery is enabled */
guint upnp_timeout; /* UPnP discovery timeout */
- GSList *upnp_mapping; /* NiceAddresses of cands being mapped */
- GSource *upnp_timer_source; /* source of upnp timeout timer */
#endif
gchar *software_attribute; /* SOFTWARE attribute */
gboolean reliable; /* property: reliable */
@@ -246,7 +244,7 @@ StunUsageIceCompatibility agent_to_ice_compatibility (NiceAgent *agent);
StunUsageTurnCompatibility agent_to_turn_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);
void nice_agent_init_stun_agent (NiceAgent *agent, StunAgent *stun_agent);
diff --git a/agent/agent.c b/agent/agent.c
index e642b63..c9c9313 100644
--- a/agent/agent.c
+++ b/agent/agent.c
@@ -145,8 +145,6 @@ enum
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_readable (PseudoTcpSocket *sock, gpointer user_data);
static void pseudo_tcp_socket_writable (PseudoTcpSocket *sock, gpointer user_data);
@@ -1630,9 +1628,7 @@ nice_agent_set_property (
break;
case PROP_UPNP:
-#ifdef HAVE_GUPNP
agent->upnp_enabled = g_value_get_boolean (value);
-#endif
break;
case PROP_RELIABLE:
@@ -2218,7 +2214,7 @@ _transport_to_string (NiceCandidateTransport type) {
void agent_gathering_done (NiceAgent *agent)
{
-
+ gboolean upnp_running = FALSE;
GSList *i, *j, *k, *l, *m;
for (i = agent->streams; i; i = i->next) {
@@ -2234,6 +2230,11 @@ void agent_gathering_done (NiceAgent *agent)
if (!stream->gathering)
continue;
+#ifdef HAVE_GUPNP
+ if (stream->upnp_timer_source != NULL)
+ upnp_running = TRUE;
+#endif
+
for (j = stream->components; j; j = j->next) {
NiceComponent *component = j->data;
@@ -2280,7 +2281,7 @@ void agent_gathering_done (NiceAgent *agent)
"for OC2007R2 compatibility", agent);
component->local_candidates =
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);
goto next_cand;
}
@@ -2305,15 +2306,8 @@ next_cand:
}
}
-#ifdef HAVE_GUPNP
- if (agent->discovery_timer_source == NULL &&
- agent->upnp_timer_source == NULL) {
- agent_signal_gathering_done (agent);
- }
-#else
- if (agent->discovery_timer_source == NULL)
+ if (agent->discovery_timer_source == NULL && !upnp_running)
agent_signal_gathering_done (agent);
-#endif
}
void agent_signal_gathering_done (NiceAgent *agent)
@@ -2908,23 +2902,6 @@ nice_agent_set_relay_info(NiceAgent *agent,
#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
* 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.
@@ -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
* mapped-external-port and error-mapping-port signals could be emitted multiple
* 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;
- 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;
+ 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;
}
agent_gathering_done (agent);
}
-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)
+static gboolean priv_upnp_timeout_cb_agent_locked (NiceAgent *agent,
+ gpointer user_data)
{
- NiceAgent *agent = (NiceAgent*)user_data;
- NiceAddress localaddr;
- NiceAddress externaddr;
- NiceCandidateTransport transport;
- GSList *i, *j, *k;
+ NiceStream *stream = user_data;
- agent_lock (agent);
+ nice_debug ("Agent %p s:%d : UPnP port mapping timed out", agent,
+ stream->id);
- if (agent->upnp_timer_source == NULL)
- goto end;
+ /* Force it to be done */
+ 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,
- local_port, external_ip, external_port);
+ check_upnp_gathering_done (agent, stream);
- if (!nice_address_set_from_string (&localaddr, local_ip))
- goto end;
- nice_address_set_port (&localaddr, local_port);
+ return G_SOURCE_REMOVE;
+}
+
+
+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)
- transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
+ if ((host_candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP) !=
+ (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
- transport = NICE_CANDIDATE_TRANSPORT_UDP;
+ upnp_candidate.transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
- for (i = agent->upnp_mapping; i; i = i->next) {
- NiceAddress *addr = i->data;
- if (nice_address_equal (&localaddr, addr)) {
- agent->upnp_mapping = g_slist_remove (agent->upnp_mapping, addr);
- nice_address_free (addr);
- break;
+ for (i = agent->streams; i; i = i->next) {
+ NiceStream *stream = i->data;
+ GSList *j;
+
+ j = priv_find_upnp_candidate (stream->upnp_mapping, &upnp_candidate);
+ 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))
- goto end;
+ return;
nice_address_set_port (&externaddr, external_port);
- for (i = agent->streams; i; i = i->next) {
- 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;
+ agent_lock (agent);
- if (agent->force_relay &&
- local_candidate->c.type != NICE_CANDIDATE_TYPE_RELAYED)
- continue;
+ stream = priv_find_candidate_for_upnp_mapping (agent, proto,
+ local_ip, local_port, FALSE, &was_mapping, &item);
- if (nice_address_equal (&localaddr, &local_candidate->c.base_addr)) {
- discovery_add_server_reflexive_candidate (
- agent,
- stream->id,
- component->id,
- &externaddr,
- transport,
- local_candidate->sockptr,
- TRUE);
- goto end;
- }
- }
+ if (stream && stream->upnp_timer_source) {
+ NiceCandidateImpl *host_candidate = item->data;
+
+ if (was_mapping) {
+ stream->upnp_mapping = g_slist_delete_link (stream->upnp_mapping, item);
+ stream->upnp_mapped = g_slist_prepend (stream->upnp_mapped,
+ host_candidate);
}
- }
- end:
- agent_check_upnp_gathering_done (agent);
+ discovery_add_server_reflexive_candidate (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);
}
@@ -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 *description, gpointer user_data)
{
- NiceAgent *agent = (NiceAgent*)user_data;
- NiceAddress localaddr;
- GSList *i;
+ NiceAgent *agent = (NiceAgent *) user_data;
+ NiceStream *stream;
+ GSList *item;
agent_lock (agent);
nice_debug ("Agent %p : Error mapping %s:%d to %d (%d) : %s", agent, local_ip,
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) {
- NiceAddress *addr = i->data;
- if (nice_address_equal (&localaddr, addr)) {
- agent->upnp_mapping = g_slist_remove (agent->upnp_mapping, addr);
- nice_address_free (addr);
- break;
- }
- }
+ stream = priv_find_candidate_for_upnp_mapping (agent, proto,
+ local_ip, local_port, TRUE, NULL, &item);
- 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);
}
+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
NICEAPI_EXPORT gboolean
@@ -3082,25 +3258,6 @@ nice_agent_gather_candidates (
nice_debug ("Agent %p : In %s mode, starting candidate gathering.", agent,
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 (agent->local_addresses == NULL) {
GList *addresses = nice_interfaces_get_local_ips (FALSE);
@@ -3156,11 +3313,6 @@ nice_agent_gather_candidates (
NiceAddress *addr = i->data;
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++) {
NiceCandidateTransport transport;
guint current_port;
@@ -3252,23 +3404,7 @@ nice_agent_gather_candidates (
nice_socket_set_writable_callback (host_candidate->sockptr,
_tcp_sock_is_writable, component);
-#ifdef HAVE_GUPNP
- 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
+ priv_add_upnp_discovery (agent, stream, (NiceCandidate *) host_candidate);
/* TODO: Add server-reflexive support for TCP candidates */
if (agent->full_mode && agent->stun_server_ip && !agent->force_relay &&
@@ -3338,7 +3474,7 @@ nice_agent_gather_candidates (
/* note: no async discoveries pending, signal that we are ready */
if (agent->discovery_unsched_items == 0 &&
#ifdef HAVE_GUPNP
- agent->upnp_mapping == NULL) {
+ stream->upnp_mapping == NULL) {
#else
TRUE) {
#endif
@@ -3355,20 +3491,14 @@ nice_agent_gather_candidates (
g_slist_free (local_addresses);
if (ret == FALSE) {
- priv_stop_upnp (agent);
+ priv_stop_upnp (agent, stream);
for (cid = 1; cid <= stream->n_components; cid++) {
NiceComponent *component = nice_stream_find_component_by_id (stream, cid);
nice_component_free_socket_sources (component);
- for (i = component->local_candidates; i; i = i->next) {
- NiceCandidate *candidate = i->data;
-
- agent_remove_local_candidate (agent, candidate);
-
- nice_candidate_free (candidate);
- }
- g_slist_free (component->local_candidates);
+ g_slist_free_full (component->local_candidates,
+ (GDestroyNotify) nice_candidate_free);
component->local_candidates = NULL;
}
discovery_prune_stream (agent, stream_id);
@@ -3379,44 +3509,6 @@ nice_agent_gather_candidates (
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)
{
if (agent->keepalive_timer_source != NULL) {
@@ -3469,6 +3561,8 @@ nice_agent_remove_stream (
return;
}
+ priv_stop_upnp (agent, stream);
+
/* note: remove items with matching stream_ids from both lists */
conn_check_prune_stream (agent, stream);
discovery_prune_stream (agent, stream_id);
@@ -5458,6 +5552,7 @@ nice_agent_dispose (GObject *object)
while (agent->streams) {
NiceStream *s = agent->streams->data;
+ priv_stop_upnp (agent, s);
nice_stream_close (agent, s);
g_object_unref (s);
@@ -5491,8 +5586,6 @@ nice_agent_dispose (GObject *object)
nice_rng_free (agent->rng);
agent->rng = NULL;
- priv_stop_upnp (agent);
-
#ifdef HAVE_GUPNP
if (agent->upnp) {
g_object_unref (agent->upnp);
diff --git a/agent/component.c b/agent/component.c
index b0e9fe0..1854779 100644
--- a/agent/component.c
+++ b/agent/component.c
@@ -197,8 +197,8 @@ nice_component_remove_socket (NiceAgent *agent, NiceComponent *cmp,
conn_check_prune_socket (agent, stream, cmp, candidate->sockptr);
nice_component_detach_socket (cmp, candidate->sockptr);
}
- agent_remove_local_candidate (agent, (NiceCandidate *) candidate);
- nice_candidate_free ((NiceCandidate *) candidate);
+ agent_remove_local_candidate (agent, stream, (NiceCandidate *) candidate);
+ nice_candidate_free ((NiceCandidate *)candidate);
cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, i);
i = next;
@@ -289,7 +289,7 @@ nice_component_clean_turn_servers (NiceAgent *agent, NiceComponent *cmp)
cmp->selected_pair.priority = 0;
cmp->turn_candidate = candidate;
} else {
- agent_remove_local_candidate (agent, (NiceCandidate *) candidate);
+ agent_remove_local_candidate (agent, stream, (NiceCandidate *) candidate);
relay_candidates = g_slist_append(relay_candidates, candidate);
}
cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, i);
@@ -324,7 +324,7 @@ nice_component_clear_selected_pair (NiceComponent *component)
/* Must be called with the agent lock held as it touches internal Component
* state. */
void
-nice_component_close (NiceAgent *agent, NiceComponent *cmp)
+nice_component_close (NiceAgent *agent, NiceStream *stream, NiceComponent *cmp)
{
IOCallbackData *data;
GOutputVector *vec;
@@ -353,7 +353,7 @@ nice_component_close (NiceAgent *agent, NiceComponent *cmp)
cmp->turn_candidate = NULL;
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);
cmp->local_candidates = g_slist_delete_link (cmp->local_candidates,
cmp->local_candidates);
diff --git a/agent/component.h b/agent/component.h
index a36cc94..2e6c496 100644
--- a/agent/component.h
+++ b/agent/component.h
@@ -236,7 +236,8 @@ NiceComponent *
nice_component_new (guint component_id, NiceAgent *agent, NiceStream *stream);
void
-nice_component_close (NiceAgent *agent, NiceComponent *component);
+nice_component_close (NiceAgent *agent, NiceStream *stream,
+ NiceComponent *component);
gboolean
nice_component_find_pair (NiceComponent *component, NiceAgent *agent,
diff --git a/agent/stream.c b/agent/stream.c
index b8f42dc..2ec4feb 100644
--- a/agent/stream.c
+++ b/agent/stream.c
@@ -89,7 +89,7 @@ nice_stream_close (NiceAgent *agent, NiceStream *stream)
for (i = stream->components; i; i = i->next) {
NiceComponent *component = i->data;
- nice_component_close (agent, component);
+ nice_component_close (agent, stream, component);
}
}
diff --git a/agent/stream.h b/agent/stream.h
index de1d456..b41f67a 100644
--- a/agent/stream.h
+++ b/agent/stream.h
@@ -90,6 +90,12 @@ struct _NiceStream {
gboolean peer_gathering_done;
gint tos;
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 {