diff options
-rw-r--r-- | libgupnp-igd/gupnp-simple-igd-priv.h | 7 | ||||
-rw-r--r-- | libgupnp-igd/gupnp-simple-igd-thread.c | 63 | ||||
-rw-r--r-- | libgupnp-igd/gupnp-simple-igd.c | 74 | ||||
-rw-r--r-- | libgupnp-igd/gupnp-simple-igd.h | 6 | ||||
-rw-r--r-- | tests/gtest/gupnp-simple-igd.c | 20 |
5 files changed, 163 insertions, 7 deletions
diff --git a/libgupnp-igd/gupnp-simple-igd-priv.h b/libgupnp-igd/gupnp-simple-igd-priv.h index 34d4cb1..0081b78 100644 --- a/libgupnp-igd/gupnp-simple-igd-priv.h +++ b/libgupnp-igd/gupnp-simple-igd-priv.h @@ -51,6 +51,13 @@ struct _GUPnPSimpleIgdClass void (*remove_port) (GUPnPSimpleIgd *self, const gchar *protocol, guint external_port); + + void (*remove_port_local) (GUPnPSimpleIgd *self, + const gchar *protocol, + const gchar *local_ip, + guint16 local_port); + + /*< private >*/ }; #endif /* __GUPNP_SIMPLE_IGD_PRIV_H__ */ diff --git a/libgupnp-igd/gupnp-simple-igd-thread.c b/libgupnp-igd/gupnp-simple-igd-thread.c index 0adb64d..178c9f2 100644 --- a/libgupnp-igd/gupnp-simple-igd-thread.c +++ b/libgupnp-igd/gupnp-simple-igd-thread.c @@ -109,6 +109,10 @@ static void gupnp_simple_igd_thread_add_port (GUPnPSimpleIgd *self, static void gupnp_simple_igd_thread_remove_port (GUPnPSimpleIgd *self, const gchar *protocol, guint external_port); +static void gupnp_simple_igd_thread_remove_port_local (GUPnPSimpleIgd *self, + const gchar *protocol, + const gchar *local_ip, + guint16 local_port); struct AddRemovePortData { @@ -138,6 +142,8 @@ gupnp_simple_igd_thread_class_init (GUPnPSimpleIgdThreadClass *klass) simple_igd_class->add_port = gupnp_simple_igd_thread_add_port; simple_igd_class->remove_port = gupnp_simple_igd_thread_remove_port; + simple_igd_class->remove_port_local = + gupnp_simple_igd_thread_remove_port_local; } @@ -282,7 +288,7 @@ thread_func (gpointer dat) struct thread_data *data = dat; GMainLoop *loop = g_main_loop_new (data->context, FALSE); - g_main_context_push_thread_default(data->context); + g_main_context_push_thread_default (data->context); g_mutex_lock (data->mutex); data->loop = loop; @@ -295,6 +301,8 @@ thread_func (gpointer dat) data->all_mappings_deleted = TRUE; g_mutex_unlock (data->mutex); + g_main_context_pop_thread_default (data->context); + g_main_loop_unref (loop); thread_data_dec (data); @@ -394,6 +402,31 @@ remove_port_idle_func (gpointer user_data) return FALSE; } +static gboolean +remove_port_local_idle_func (gpointer user_data) +{ + struct AddRemovePortData *data = user_data; + GUPnPSimpleIgdClass *klass = + GUPNP_SIMPLE_IGD_CLASS (gupnp_simple_igd_thread_parent_class); + GUPnPSimpleIgdThread *self; + + g_static_mutex_lock (&data->mutex); + self = data->self; + if (self) + g_object_ref (self); + g_static_mutex_unlock (&data->mutex); + if (!self) + return FALSE; + + if (klass->remove_port_local) + klass->remove_port_local (GUPNP_SIMPLE_IGD (self), data->protocol, + data->local_ip, data->local_port); + + g_object_unref (self); + + return FALSE; +} + static void free_add_remove_port_data (gpointer user_data) { @@ -481,6 +514,34 @@ gupnp_simple_igd_thread_remove_port (GUPnPSimpleIgd *self, g_main_context_wakeup (realself->priv->context); } +static void +gupnp_simple_igd_thread_remove_port_local (GUPnPSimpleIgd *self, + const gchar *protocol, + const gchar *local_ip, + guint16 local_port) +{ + GUPnPSimpleIgdThread *realself = GUPNP_SIMPLE_IGD_THREAD (self); + struct AddRemovePortData *data = g_slice_new0 (struct AddRemovePortData); + GSource *source; + + g_static_mutex_init (&data->mutex); + data->self = realself; + data->protocol = g_strdup (protocol); + data->local_ip = g_strdup (local_ip); + data->local_port = local_port; + GUPNP_SIMPLE_IGD_THREAD_LOCK (realself); + g_ptr_array_add (realself->priv->add_remove_port_datas, data); + GUPNP_SIMPLE_IGD_THREAD_UNLOCK (realself); + + source = g_idle_source_new (); + g_source_set_callback (source, remove_port_local_idle_func, data, + free_add_remove_port_data); + g_source_set_priority (source, G_PRIORITY_DEFAULT); + g_source_attach (source, realself->priv->context); + g_source_unref (source); + g_main_context_wakeup (realself->priv->context); +} + /** * gupnp_simple_igd_thread_new: * diff --git a/libgupnp-igd/gupnp-simple-igd.c b/libgupnp-igd/gupnp-simple-igd.c index 775c4d3..61d1e77 100644 --- a/libgupnp-igd/gupnp-simple-igd.c +++ b/libgupnp-igd/gupnp-simple-igd.c @@ -154,6 +154,10 @@ static void gupnp_simple_igd_add_port_real (GUPnPSimpleIgd *self, static void gupnp_simple_igd_remove_port_real (GUPnPSimpleIgd *self, const gchar *protocol, guint external_port); +static void gupnp_simple_igd_remove_port_local_real (GUPnPSimpleIgd *self, + const gchar *protocol, + const gchar *local_ip, + guint16 local_port); GQuark gupnp_simple_igd_error_quark (void) @@ -176,6 +180,7 @@ gupnp_simple_igd_class_init (GUPnPSimpleIgdClass *klass) klass->add_port = gupnp_simple_igd_add_port_real; klass->remove_port = gupnp_simple_igd_remove_port_real; + klass->remove_port_local = gupnp_simple_igd_remove_port_local_real; g_object_class_install_property (gobject_class, PROP_MAIN_CONTEXT, @@ -852,9 +857,6 @@ gupnp_simple_igd_add_port_real (GUPnPSimpleIgd *self, struct Mapping *mapping = g_slice_new0 (struct Mapping); guint i; - g_return_if_fail (protocol && local_ip); - g_return_if_fail (!strcmp (protocol, "UDP") || !strcmp (protocol, "TCP")); - mapping->protocol = g_strdup (protocol); mapping->requested_external_port = external_port; mapping->local_ip = g_strdup (local_ip); @@ -902,8 +904,9 @@ gupnp_simple_igd_add_port_real (GUPnPSimpleIgd *self, * @description: The description that will appear in the router's table * * This adds a port to the router's forwarding table. The mapping will - * be automatically refreshed by this object until it is either removed with - * gupnp_simple_igd_remove_port() or the object disapears. + * be automatically refreshed by this object until it is either + * removed with gupnp_simple_igd_remove_port(), + * gupnp_simple_igd_remove_port_local() or the object disapears. * * If there is a problem, the #GUPnPSimpleIgd::error-mapping-port signal will * be emitted. If a router is found and a port is mapped correctly, @@ -985,6 +988,67 @@ gupnp_simple_igd_remove_port (GUPnPSimpleIgd *self, klass->remove_port (self, protocol, external_port); } + +static void +gupnp_simple_igd_remove_port_local_real (GUPnPSimpleIgd *self, + const gchar *protocol, + const gchar *local_ip, + guint16 local_port) +{ + struct Mapping *mapping = NULL; + guint i; + + for (i = 0; i < self->priv->mappings->len; i++) + { + struct Mapping *tmpmapping = g_ptr_array_index (self->priv->mappings, i); + if (tmpmapping->local_port == local_port && + !strcmp (tmpmapping->local_ip, local_ip) && + !strcmp (tmpmapping->protocol, protocol)) + { + mapping = tmpmapping; + break; + } + } + if (!mapping) + return; + + g_ptr_array_remove_index_fast (self->priv->mappings, i); + + free_mapping (self, mapping); +} + +/** + * gupnp_simple_igd_remove_port_local: + * @self: The #GUPnPSimpleIgd object + * @protocol: the protocol "UDP" or "TCP" as given to + * gupnp_simple_igd_add_port() + * @local_ip: The local ip on the internal device as was to + * gupnp_simple_igd_add_port() + * @local_port: The port to try to open on the internal device as given to + * gupnp_simple_igd_add_port() + * + * This tries to remove a port entry from the routers that was previously added + * with gupnp_simple_igd_add_port(). There is no indicated of success or failure + * it is a best effort mechanism. If it fails, the bindings will disapears after + * the lease duration set when the port where added. + */ +void +gupnp_simple_igd_remove_port_local (GUPnPSimpleIgd *self, + const gchar *protocol, + const gchar *local_ip, + guint16 local_port) +{ + GUPnPSimpleIgdClass *klass = GUPNP_SIMPLE_IGD_GET_CLASS (self); + + g_return_if_fail (protocol != NULL); + g_return_if_fail (local_ip != NULL); + g_return_if_fail (local_port != 0); + + g_return_if_fail (klass->remove_port_local); + + klass->remove_port_local (self, protocol, local_ip, local_port); +} + static void stop_proxymapping (struct ProxyMapping *pm, gboolean stop_renew) { diff --git a/libgupnp-igd/gupnp-simple-igd.h b/libgupnp-igd/gupnp-simple-igd.h index 96d096a..d0acd8f 100644 --- a/libgupnp-igd/gupnp-simple-igd.h +++ b/libgupnp-igd/gupnp-simple-igd.h @@ -100,6 +100,12 @@ gupnp_simple_igd_remove_port (GUPnPSimpleIgd *self, const gchar *protocol, guint external_port); +void +gupnp_simple_igd_remove_port_local (GUPnPSimpleIgd *self, + const gchar *protocol, + const gchar *local_ip, + guint16 local_port); + gboolean gupnp_simple_igd_delete_all_mappings (GUPnPSimpleIgd *self); diff --git a/tests/gtest/gupnp-simple-igd.c b/tests/gtest/gupnp-simple-igd.c index fe2aa7f..9b32b2a 100644 --- a/tests/gtest/gupnp-simple-igd.c +++ b/tests/gtest/gupnp-simple-igd.c @@ -50,6 +50,7 @@ static GUPnPServiceInfo *pppservice = NULL; gboolean return_conflict = FALSE; gboolean dispose_removes = FALSE; +gboolean local_remove = FALSE; gchar *invalid_ip = NULL; static void @@ -210,8 +211,10 @@ mapped_external_port_cb (GUPnPSimpleIgd *igd, gchar *proto, !strcmp (external_ip, PPP_ADDRESS_SECOND))); if (dispose_removes) g_object_unref (igd); + else if (local_remove) + gupnp_simple_igd_remove_port_local (igd, proto, local_ip, local_port); else - gupnp_simple_igd_remove_port (igd, "UDP", requested_external_port); + gupnp_simple_igd_remove_port (igd, proto, requested_external_port); } else { @@ -360,6 +363,19 @@ test_gupnp_simple_igd_default_ctx (void) } static void +test_gupnp_simple_igd_default_ctx_local (void) +{ + GUPnPSimpleIgd *igd = gupnp_simple_igd_new (); + + local_remove = TRUE; + + run_gupnp_simple_igd_test (NULL, igd, INTERNAL_PORT); + g_object_unref (igd); + + local_remove = FALSE; +} + +static void test_gupnp_simple_igd_custom_ctx (void) { GMainContext *mainctx = g_main_context_new (); @@ -463,6 +479,8 @@ int main (int argc, char **argv) g_test_add_func("/simpleigd/new", test_gupnp_simple_igd_new); g_test_add_func ("/simpleigd/default_ctx", test_gupnp_simple_igd_default_ctx); + g_test_add_func ("/simpleigd/default_ctx/remove_local", + test_gupnp_simple_igd_default_ctx_local); g_test_add_func ("/simpleigd/custom_ctx", test_gupnp_simple_igd_custom_ctx); g_test_add_func ("/simpleigd/thread", test_gupnp_simple_igd_thread); g_test_add_func ("/simpleigd/random/no_conflict", |