[farsight2/master] Move upnp stuff in fs2 places

Olivier Crête olivier.crete at collabora.co.uk
Tue Dec 23 15:25:05 PST 2008


---
 Makefile                                           |   29 -
 fs-upnp-simple-igd-marshal.list                    |    2 -
 fs-upnp-simple-igd-thread.c                        |  255 ------
 fs-upnp-simple-igd-thread.h                        |   88 --
 fs-upnp-simple-igd.c                               |  842 --------------------
 fs-upnp-simple-igd.h                               |  116 ---
 .../fssimpleupnp/fs-upnp-simple-igd-marshal.list   |    2 +
 .../ext/fssimpleupnp/fs-upnp-simple-igd-thread.c   |  255 ++++++
 .../ext/fssimpleupnp/fs-upnp-simple-igd-thread.h   |   88 ++
 gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd.c     |  842 ++++++++++++++++++++
 gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd.h     |  116 +++
 test-thread.c                                      |   85 --
 test.c                                             |   98 ---
 tests/commandline/test-thread.c                    |   85 ++
 tests/commandline/test.c                           |   98 +++
 15 files changed, 1486 insertions(+), 1515 deletions(-)
 delete mode 100644 Makefile
 delete mode 100644 fs-upnp-simple-igd-marshal.list
 delete mode 100644 fs-upnp-simple-igd-thread.c
 delete mode 100644 fs-upnp-simple-igd-thread.h
 delete mode 100644 fs-upnp-simple-igd.c
 delete mode 100644 fs-upnp-simple-igd.h
 create mode 100644 gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd-marshal.list
 create mode 100644 gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd-thread.c
 create mode 100644 gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd-thread.h
 create mode 100644 gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd.c
 create mode 100644 gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd.h
 delete mode 100644 test-thread.c
 delete mode 100644 test.c
 create mode 100644 tests/commandline/test-thread.c
 create mode 100644 tests/commandline/test.c

diff --git a/Makefile b/Makefile
deleted file mode 100644
index 7e8842d..0000000
--- a/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
-
-all: test test-thread
-
-CFLAGS = -g -Wextra -Wall -Wno-unused-parameter -Wno-missing-field-initializers `pkg-config --cflags gupnp-1.0`
-LDFLAGS =  `pkg-config --libs gupnp-1.0`
-
-fs-upnp-simple-igd.o: fs-upnp-simple-igd-marshal.h fs-upnp-simple-igd.c fs-upnp-simple-igd.h
-
-fs-upnp-simple-igd-thread.o: fs-upnp-simple-igd-thread.c fs-upnp-simple-igd-thread.h
-
-test: fs-upnp-simple-igd-marshal.o fs-upnp-simple-igd.o test.o 
-
-test-thread: fs-upnp-simple-igd-thread.o fs-upnp-simple-igd-marshal.o fs-upnp-simple-igd.o test-thread.o 
-
-clean:
-	rm -f *.o test test-thread *-marshal.[ch]
-
-SOURCES = fs-upnp-simple-igd.c
-srcdir = .
-
-fs-upnp-simple-igd-marshal.h: fs-upnp-simple-igd-marshal.list Makefile
-	glib-genmarshal --header --prefix=_fs_upnp_simple_igd_marshal $(srcdir)/$< > $@.tmp
-	mv $@.tmp $@
-
-fs-upnp-simple-igd-marshal.c: fs-upnp-simple-igd-marshal.list Makefile
-	echo "#include \"glib-object.h\"" >> $@.tmp
-	echo "#include \"fs-upnp-simple-igd-marshal.h\"" >> $@.tmp
-	glib-genmarshal --body --prefix=_fs_upnp_simple_igd_marshal $(srcdir)/$< >> $@.tmp
-	mv $@.tmp $@
diff --git a/fs-upnp-simple-igd-marshal.list b/fs-upnp-simple-igd-marshal.list
deleted file mode 100644
index 8b8f99c..0000000
--- a/fs-upnp-simple-igd-marshal.list
+++ /dev/null
@@ -1,2 +0,0 @@
-VOID:STRING,STRING,STRING,UINT,STRING,UINT,STRING
-VOID:POINTER,STRING,UINT,STRING
diff --git a/fs-upnp-simple-igd-thread.c b/fs-upnp-simple-igd-thread.c
deleted file mode 100644
index 1589639..0000000
--- a/fs-upnp-simple-igd-thread.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Farsight2 - Farsight UPnP IGD abstraction
- *
- * Copyright 2008 Collabora Ltd.
- *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
- * Copyright 2008 Nokia Corp.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-
-#include "fs-upnp-simple-igd-thread.h"
-
-
-struct _FsUpnpSimpleIgdThreadPrivate
-{
-  GThread *thread;
-  GMainLoop *loop;
-  GMainContext *context;
-  GMutex *mutex;
-};
-
-
-#define FS_UPNP_SIMPLE_IGD_THREAD_GET_PRIVATE(o)                        \
-  (G_TYPE_INSTANCE_GET_PRIVATE ((o), FS_TYPE_UPNP_SIMPLE_IGD_THREAD,    \
-   FsUpnpSimpleIgdThreadPrivate))
-
-#define FS_UPNP_SIMPLE_IGD_THREAD_LOCK(o)   g_mutex_lock ((o)->priv->mutex)
-#define FS_UPNP_SIMPLE_IGD_THREAD_UNLOCK(o) g_mutex_unlock ((o)->priv->mutex)
-
-
-G_DEFINE_TYPE (FsUpnpSimpleIgdThread, fs_upnp_simple_igd_thread,
-    FS_TYPE_UPNP_SIMPLE_IGD);
-
-static void fs_upnp_simple_igd_thread_constructed (GObject *object);
-static void fs_upnp_simple_igd_thread_dispose (GObject *object);
-static void fs_upnp_simple_igd_thread_finalize (GObject *object);
-
-static void fs_upnp_simple_igd_thread_add_port (FsUpnpSimpleIgd *self,
-    const gchar *protocol,
-    guint16 external_port,
-    const gchar *local_ip,
-    guint16 local_port,
-    guint32 lease_duration,
-    const gchar *description);
-static void fs_upnp_simple_igd_thread_remove_port (FsUpnpSimpleIgd *self,
-    const gchar *protocol,
-    guint external_port);
-
-static void
-fs_upnp_simple_igd_thread_class_init (FsUpnpSimpleIgdThreadClass *klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  FsUpnpSimpleIgdClass *simple_igd_class = FS_UPNP_SIMPLE_IGD_CLASS (klass);
-
-  g_type_class_add_private (klass, sizeof (FsUpnpSimpleIgdThreadPrivate));
-
-  gobject_class->constructed = fs_upnp_simple_igd_thread_constructed;
-  gobject_class->dispose = fs_upnp_simple_igd_thread_dispose;
-  gobject_class->finalize = fs_upnp_simple_igd_thread_finalize;
-
-  simple_igd_class->add_port = fs_upnp_simple_igd_thread_add_port;
-  simple_igd_class->remove_port = fs_upnp_simple_igd_thread_remove_port;
-}
-
-
-static void
-fs_upnp_simple_igd_thread_init (FsUpnpSimpleIgdThread *self)
-{
-  self->priv = FS_UPNP_SIMPLE_IGD_THREAD_GET_PRIVATE (self);
-
-  self->priv->mutex = g_mutex_new ();
-  self->priv->context = g_main_context_new ();
-
-  g_object_set (self, "main-context", self->priv->context, NULL);
-}
-
-
-static void
-fs_upnp_simple_igd_thread_dispose (GObject *object)
-{
-  FsUpnpSimpleIgdThread *self = FS_UPNP_SIMPLE_IGD_THREAD_CAST (object);
-
-  FS_UPNP_SIMPLE_IGD_THREAD_LOCK (self);
-  if (self->priv->loop)
-    g_main_loop_quit (self->priv->loop);
-  FS_UPNP_SIMPLE_IGD_THREAD_UNLOCK (self);
-
-  g_thread_join (self->priv->thread);
-  self->priv->thread = NULL;
-
-  G_OBJECT_CLASS (fs_upnp_simple_igd_thread_parent_class)->dispose (object);
-}
-
-static void
-fs_upnp_simple_igd_thread_finalize (GObject *object)
-{
-  FsUpnpSimpleIgdThread *self = FS_UPNP_SIMPLE_IGD_THREAD_CAST (object);
-
-  g_main_context_unref (self->priv->context);
-  g_mutex_free (self->priv->mutex);
-
-  G_OBJECT_CLASS (fs_upnp_simple_igd_thread_parent_class)->finalize (object);
-}
-
-static gpointer
-thread_func (gpointer data)
-{
-  FsUpnpSimpleIgdThread *self = data;
-  GMainLoop *loop = g_main_loop_new (self->priv->context, FALSE);
-  FS_UPNP_SIMPLE_IGD_THREAD_LOCK (self);
-  self->priv->loop = loop;
-  FS_UPNP_SIMPLE_IGD_THREAD_UNLOCK (self);
-
-  g_main_loop_run (loop);
-
-  FS_UPNP_SIMPLE_IGD_THREAD_LOCK (self);
-  self->priv->loop = NULL;
-  FS_UPNP_SIMPLE_IGD_THREAD_UNLOCK (self);
-
-  g_main_loop_unref (loop);
-
-  return NULL;
-}
-
-static void
-fs_upnp_simple_igd_thread_constructed (GObject *object)
-{
-  FsUpnpSimpleIgdThread *self = FS_UPNP_SIMPLE_IGD_THREAD_CAST (object);
-
-  if (G_OBJECT_CLASS (fs_upnp_simple_igd_thread_parent_class)->constructed)
-    G_OBJECT_CLASS (fs_upnp_simple_igd_thread_parent_class)->constructed (object);
-
-  self->priv->thread = g_thread_create (thread_func, self, TRUE, NULL);
-  g_return_if_fail (self->priv->thread);
-}
-
-struct AddRemovePortData {
-  FsUpnpSimpleIgd *self;
-  gchar *protocol;
-  guint16 external_port;
-  gchar *local_ip;
-  guint16 local_port;
-  guint32 lease_duration;
-  gchar *description;
-};
-
-static gboolean
-add_port_idle_func (gpointer user_data)
-{
-  struct AddRemovePortData *data = user_data;
-  FsUpnpSimpleIgdClass *klass =
-      FS_UPNP_SIMPLE_IGD_CLASS (fs_upnp_simple_igd_thread_parent_class);
-
-  if (klass->add_port)
-    klass->add_port (data->self, data->protocol, data->external_port,
-        data->local_ip, data->local_port, data->lease_duration,
-        data->description);
-
-  return FALSE;
-}
-
-
-static gboolean
-remove_port_idle_func (gpointer user_data)
-{
-  struct AddRemovePortData *data = user_data;
-  FsUpnpSimpleIgdClass *klass =
-      FS_UPNP_SIMPLE_IGD_CLASS (fs_upnp_simple_igd_thread_parent_class);
-
-  if (klass->remove_port)
-    klass->remove_port (data->self, data->protocol, data->external_port);
-
-  return FALSE;
-}
-
-static void
-free_add_remove_port_data (gpointer user_data)
-{
-  struct AddRemovePortData *data = user_data;
-
-  g_object_unref (data->self);
-  g_free (data->protocol);
-  g_free (data->local_ip);
-  g_free (data->description);
-
-  g_slice_free (struct AddRemovePortData, data);
-}
-
-static void
-fs_upnp_simple_igd_thread_add_port (FsUpnpSimpleIgd *self,
-    const gchar *protocol,
-    guint16 external_port,
-    const gchar *local_ip,
-    guint16 local_port,
-    guint32 lease_duration,
-    const gchar *description)
-{
-  FsUpnpSimpleIgdThread *realself = FS_UPNP_SIMPLE_IGD_THREAD (self);
-  struct AddRemovePortData *data = g_slice_new0 (struct AddRemovePortData);
-  GSource *source;
-
-  data->self = g_object_ref (self);
-  data->protocol = g_strdup (protocol);
-  data->external_port = external_port;
-  data->local_ip = g_strdup (local_ip);
-  data->local_port = local_port;
-  data->lease_duration = lease_duration;
-  data->description = g_strdup (description);
-
-  source = g_idle_source_new ();
-  g_source_set_callback (source, add_port_idle_func, data,
-      free_add_remove_port_data);
-  g_source_attach (source, realself->priv->context);
-  g_main_context_wakeup (realself->priv->context);
-}
-
-static void
-fs_upnp_simple_igd_thread_remove_port (FsUpnpSimpleIgd *self,
-    const gchar *protocol,
-    guint external_port)
-{
-  FsUpnpSimpleIgdThread *realself = FS_UPNP_SIMPLE_IGD_THREAD (self);
-  struct AddRemovePortData *data = g_slice_new0 (struct AddRemovePortData);
-  GSource *source;
-
-  data->self = g_object_ref (self);
-  data->protocol = g_strdup (protocol);
-  data->external_port = external_port;
-
-  source = g_idle_source_new ();
-  g_source_set_callback (source, remove_port_idle_func, data,
-      free_add_remove_port_data);
-  g_source_attach (source, realself->priv->context);
-  g_main_context_wakeup (realself->priv->context);
-}
-
-
-FsUpnpSimpleIgdThread *
-fs_upnp_simple_igd_thread_new ()
-{
-  return g_object_new (FS_TYPE_UPNP_SIMPLE_IGD_THREAD, NULL);
-}
diff --git a/fs-upnp-simple-igd-thread.h b/fs-upnp-simple-igd-thread.h
deleted file mode 100644
index b3253e4..0000000
--- a/fs-upnp-simple-igd-thread.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Farsight2 - Farsight UPnP IGD abstraction
- *
- * Copyright 2008 Collabora Ltd.
- *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
- * Copyright 2008 Nokia Corp.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef __FS_UPNP_SIMPLE_IGD_THREAD_H__
-#define __FS_UPNP_SIMPLE_IGD_THREAD_H__
-
-#include "fs-upnp-simple-igd.h"
-
-G_BEGIN_DECLS
-
-/* TYPE MACROS */
-#define FS_TYPE_UPNP_SIMPLE_IGD_THREAD       \
-  (fs_upnp_simple_igd_thread_get_type ())
-#define FS_UPNP_SIMPLE_IGD_THREAD(obj)                               \
-  (G_TYPE_CHECK_INSTANCE_CAST((obj), FS_TYPE_UPNP_SIMPLE_IGD_THREAD, \
-      FsUpnpSimpleIgdThread))
-#define FS_UPNP_SIMPLE_IGD_THREAD_CLASS(klass)                       \
-  (G_TYPE_CHECK_CLASS_CAST((klass), FS_TYPE_UPNP_SIMPLE_IGD_THREAD,  \
-      FsUpnpSimpleIgdThreadClass))
-#define FS_IS_UPNP_SIMPLE_IGD_THREAD(obj)                            \
-  (G_TYPE_CHECK_INSTANCE_TYPE((obj), FS_TYPE_UPNP_SIMPLE_IGD_THREAD))
-#define FS_IS_UPNP_SIMPLE_IGD_THREAD_CLASS(klass)                    \
-  (G_TYPE_CHECK_CLASS_TYPE((klass), FS_TYPE_UPNP_SIMPLE_IGD_THREAD))
-#define FS_UPNP_SIMPLE_IGD_THREAD_GET_CLASS(obj)                     \
-  (G_TYPE_INSTANCE_GET_CLASS ((obj), FS_TYPE_UPNP_SIMPLE_IGD_THREAD, \
-      FsUpnpSimpleIgdThreadClass))
-#define FS_UPNP_SIMPLE_IGD_THREAD_CAST(obj)                          \
-  ((FsUpnpSimpleIgdThread *) (obj))
-
-typedef struct _FsUpnpSimpleIgdThread FsUpnpSimpleIgdThread;
-typedef struct _FsUpnpSimpleIgdThreadClass FsUpnpSimpleIgdThreadClass;
-typedef struct _FsUpnpSimpleIgdThreadPrivate FsUpnpSimpleIgdThreadPrivate;
-
-/**
- * FsUpnpSimpleIgdThreadClass:
- * @parent_class: Our parent
- *
- * The Raw UDP component transmitter class
- */
-
-struct _FsUpnpSimpleIgdThreadClass
-{
-  FsUpnpSimpleIgdClass parent_class;
-
-  /*virtual functions */
-  /*< private >*/
-};
-
-/**
- * FsUpnpSimpleIgdThread:
- *
- * All members are private, access them using methods and properties
- */
-struct _FsUpnpSimpleIgdThread
-{
-  FsUpnpSimpleIgd parent;
-
-  /*< private >*/
-  FsUpnpSimpleIgdThreadPrivate *priv;
-};
-
-GType fs_upnp_simple_igd_thread_get_type (void);
-
-FsUpnpSimpleIgdThread *
-fs_upnp_simple_igd_thread_new (void);
-
-G_END_DECLS
-
-#endif /* __FS_UPNP_SIMPLE_IGD_THREAD_H__ */
diff --git a/fs-upnp-simple-igd.c b/fs-upnp-simple-igd.c
deleted file mode 100644
index f342454..0000000
--- a/fs-upnp-simple-igd.c
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * Farsight2 - Farsight UPnP IGD abstraction
- *
- * Copyright 2008 Collabora Ltd.
- *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
- * Copyright 2008 Nokia Corp.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-
-#include "fs-upnp-simple-igd.h"
-#include "fs-upnp-simple-igd-marshal.h"
-
-#include <string.h>
-
-#include <libgupnp/gupnp-control-point.h>
-
-
-struct _FsUpnpSimpleIgdPrivate
-{
-  GMainContext *main_context;
-
-  GUPnPContext *gupnp_context;
-  GUPnPControlPoint *cp;
-
-  GPtrArray *service_proxies;
-
-  GPtrArray *mappings;
-
-  gulong avail_handler;
-  gulong unavail_handler;
-
-  guint request_timeout;
-};
-
-struct Proxy {
-  FsUpnpSimpleIgd *parent;
-  GUPnPServiceProxy *proxy;
-
-  gchar *external_ip;
-  GUPnPServiceProxyAction *external_ip_action;
-
-  GPtrArray *proxymappings;
-};
-
-struct Mapping {
-  gchar *protocol;
-  guint external_port;
-  gchar *local_ip;
-  guint16 local_port;
-  guint32 lease_duration;
-  gchar *description;
-};
-
-struct ProxyMapping {
-  struct Proxy *proxy;
-  struct Mapping *mapping;
-
-  GUPnPServiceProxyAction *action;
-  GSource *timeout_src;
-
-  gboolean mapped;
-
-  GSource *renew_src;
-};
-
-/* signals */
-enum
-{
-  SIGNAL_NEW_EXTERNAL_IP,
-  SIGNAL_MAPPED_EXTERNAL_PORT,
-  SIGNAL_ERROR_MAPPING_PORT,
-  SIGNAL_ERROR,
-  LAST_SIGNAL
-};
-
-/* props */
-enum
-{
-  PROP_0,
-  PROP_REQUEST_TIMEOUT,
-  PROP_MAIN_CONTEXT
-};
-
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-
-#define FS_UPNP_SIMPLE_IGD_GET_PRIVATE(o)                                 \
-  (G_TYPE_INSTANCE_GET_PRIVATE ((o), FS_TYPE_UPNP_SIMPLE_IGD,             \
-   FsUpnpSimpleIgdPrivate))
-
-
-G_DEFINE_TYPE (FsUpnpSimpleIgd, fs_upnp_simple_igd, G_TYPE_OBJECT);
-
-
-static void fs_upnp_simple_igd_constructed (GObject *object);
-static void fs_upnp_simple_igd_dispose (GObject *object);
-static void fs_upnp_simple_igd_finalize (GObject *object);
-static void fs_upnp_simple_igd_get_property (GObject *object, guint prop_id,
-    GValue *value, GParamSpec *pspec);
-static void fs_upnp_simple_igd_set_property (GObject *object, guint prop_id,
-    const GValue *value, GParamSpec *pspec);
-
-static void fs_upnp_simple_igd_gather (FsUpnpSimpleIgd *self,
-    struct Proxy *prox);
-static void fs_upnp_simple_igd_add_proxy_mapping (FsUpnpSimpleIgd *self,
-    struct Proxy *prox,
-    struct Mapping *mapping);
-
-static void free_proxy (struct Proxy *prox);
-static void free_mapping (struct Mapping *mapping);
-
-static void stop_proxymapping (struct ProxyMapping *pm);
-
-static void fs_upnp_simple_igd_add_port_real (FsUpnpSimpleIgd *self,
-    const gchar *protocol,
-    guint16 external_port,
-    const gchar *local_ip,
-    guint16 local_port,
-    guint32 lease_duration,
-    const gchar *description);
-static void fs_upnp_simple_igd_remove_port_real (FsUpnpSimpleIgd *self,
-    const gchar *protocol,
-    guint external_port);
-
-
-static void
-fs_upnp_simple_igd_class_init (FsUpnpSimpleIgdClass *klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
-  g_type_class_add_private (klass, sizeof (FsUpnpSimpleIgdPrivate));
-
-  gobject_class->constructed = fs_upnp_simple_igd_constructed;
-  gobject_class->dispose = fs_upnp_simple_igd_dispose;
-  gobject_class->finalize = fs_upnp_simple_igd_finalize;
-  gobject_class->set_property = fs_upnp_simple_igd_set_property;
-  gobject_class->get_property = fs_upnp_simple_igd_get_property;
-
-  klass->add_port = fs_upnp_simple_igd_add_port_real;
-  klass->remove_port = fs_upnp_simple_igd_remove_port_real;
-
-  g_object_class_install_property (gobject_class,
-      PROP_REQUEST_TIMEOUT,
-      g_param_spec_uint ("request-timeout",
-          "The timeout after which a request is considered to have failed",
-          "After this timeout, the request is considered to have failed and"
-          "is dropped (in seconds).",
-          0, G_MAXUINT, 5,
-          G_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
-      PROP_MAIN_CONTEXT,
-      g_param_spec_pointer ("main-context",
-          "The GMainContext to use",
-          "This GMainContext will be used for all async activities",
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
-   /**
-   * FsUpnpSimpleIgd::new-external-ip
-   * @self: #FsUpnpSimpleIgd that emitted the signal
-   * @ip: The string representing the new external IP
-   *
-   * This signal means that a new external IP has been found on an IGD.
-   *
-   */
-  signals[SIGNAL_NEW_EXTERNAL_IP] = g_signal_new ("new-external-ip",
-      G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST,
-      0,
-      NULL,
-      NULL,
-      g_cclosure_marshal_VOID__STRING,
-      G_TYPE_NONE, 1, G_TYPE_STRING);
-
-
-  /**
-   * FsUpnpSimpleIgd::mapped-external-port
-   * @self: #FsUpnpSimpleIgd that emitted the signal
-   * @proto: the requested protocol ("UDP" or "TCP")
-   * @external_ip: the external IP
-   * @replaces_external_ip: if this mapping replaces another mapping,
-   *  this is the old external IP
-   * @external_port: the external port
-   * @local_ip: internal ip this is forwarded to
-   * @local_port: the local port
-   * @description: the user's selected description
-   * @ip: The string representing the new external IP
-   *
-   * This signal means that an IGD has been found that that adding a port
-   * mapping has succeeded.
-   *
-   */
-  signals[SIGNAL_MAPPED_EXTERNAL_PORT] = g_signal_new ("mapped-external-port",
-      G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST,
-      0,
-      NULL,
-      NULL,
-      _fs_upnp_simple_igd_marshal_VOID__STRING_STRING_STRING_UINT_STRING_UINT_STRING,
-      G_TYPE_NONE, 7, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT,
-      G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING);
-
-  /**
-   * FsUpnpSimpleIgd::error-mapping-port
-   * @self: #FsUpnpSimpleIgd that emitted the signal
-   * @error: a #GError or %NULL if its a timeout
-   * @proto: The requested protocol
-   * @external_port: the requested external port
-   * @description: the passed description
-   *
-   * This means that mapping a port on a specific IGD has failed (it may still
-   * succeed on other IGDs on the network).
-   */
-  signals[SIGNAL_ERROR_MAPPING_PORT] = g_signal_new ("error-mapping-port",
-      G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-      0,
-      NULL,
-      NULL,
-      _fs_upnp_simple_igd_marshal_VOID__POINTER_STRING_UINT_STRING,
-      G_TYPE_NONE, 4, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_UINT,
-      G_TYPE_STRING);
-
-  /**
-   * FsUpnpSimpleIgd::error
-   * @self: #FsUpnpSimpleIgd that emitted the signal
-   * @error: a #GError
-   *
-   * This means that an asynchronous error has happened.
-   *
-   */
-  signals[SIGNAL_ERROR] = g_signal_new ("error",
-      G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-      0,
-      NULL,
-      NULL,
-      g_cclosure_marshal_VOID__POINTER,
-      G_TYPE_NONE, 1, G_TYPE_POINTER);
-}
-
-static void
-fs_upnp_simple_igd_init (FsUpnpSimpleIgd *self)
-{
-  self->priv = FS_UPNP_SIMPLE_IGD_GET_PRIVATE (self);
-
-  self->priv->request_timeout = 5;
-
-  self->priv->service_proxies = g_ptr_array_new ();
-  self->priv->mappings = g_ptr_array_new ();
-}
-
-static void
-fs_upnp_simple_igd_dispose (GObject *object)
-{
-  FsUpnpSimpleIgd *self = FS_UPNP_SIMPLE_IGD_CAST (object);
-
-  if (self->priv->avail_handler)
-    g_signal_handler_disconnect (self->priv->cp, self->priv->avail_handler);
-  self->priv->avail_handler = 0;
-
-  if (self->priv->unavail_handler)
-    g_signal_handler_disconnect (self->priv->cp, self->priv->unavail_handler);
-  self->priv->unavail_handler = 0;
-
-  while (self->priv->mappings->len)
-  {
-    free_mapping (
-        g_ptr_array_index (self->priv->mappings, 0));
-    g_ptr_array_remove_index_fast (self->priv->mappings, 0);
-  }
-
-  while (self->priv->service_proxies->len)
-  {
-    free_proxy (
-        g_ptr_array_index (self->priv->service_proxies, 0));
-    g_ptr_array_remove_index_fast (self->priv->service_proxies, 0);
-  }
-
-  if (self->priv->cp)
-    g_object_unref (self->priv->cp);
-  self->priv->cp = NULL;
-
-  if (self->priv->gupnp_context)
-    g_object_unref (self->priv->gupnp_context);
-  self->priv->gupnp_context = NULL;
-
-  G_OBJECT_CLASS (fs_upnp_simple_igd_parent_class)->dispose (object);
-}
-
-
-static void
-_external_ip_address_changed (GUPnPServiceProxy *proxy, const gchar *variable,
-    GValue *value, gpointer user_data)
-{
-  struct Proxy *prox = user_data;
-  gchar *new_ip;
-  guint i;
-
-  g_return_if_fail (G_VALUE_HOLDS_STRING(value));
-
-  new_ip = g_value_dup_string (value);
-
-  for (i=0; i < prox->proxymappings->len; i++)
-  {
-    struct ProxyMapping *pm = g_ptr_array_index (prox->proxymappings, i);
-
-    if (pm->mapped)
-      g_signal_emit (prox->parent, signals[SIGNAL_MAPPED_EXTERNAL_PORT], 0,
-          pm->mapping->protocol, new_ip, prox->external_ip,
-          pm->mapping->external_port, pm->mapping->local_ip,
-          pm->mapping->local_port, pm->mapping->description);
-  }
-
-  g_free (prox->external_ip);
-  prox->external_ip = new_ip;
-}
-
-static void
-free_proxy (struct Proxy *prox)
-{
-  if (prox->external_ip_action)
-    gupnp_service_proxy_cancel_action (prox->proxy, prox->external_ip_action);
-
-  gupnp_service_proxy_remove_notify (prox->proxy, "ExternalIPAddress",
-      _external_ip_address_changed, prox);
-
-  g_object_unref (prox->proxy);
-  g_ptr_array_foreach (prox->proxymappings, (GFunc) stop_proxymapping, NULL);
-  g_ptr_array_free (prox->proxymappings, TRUE);
-  g_slice_free (struct Proxy, prox);
-}
-
-static void
-free_mapping (struct Mapping *mapping)
-{
-  g_free (mapping->protocol);
-  g_free (mapping->local_ip);
-  g_free (mapping->description);
-  g_slice_free (struct Mapping, mapping);
-}
-
-static void
-fs_upnp_simple_igd_finalize (GObject *object)
-{
-  FsUpnpSimpleIgd *self = FS_UPNP_SIMPLE_IGD_CAST (object);
-
-  g_main_context_unref (self->priv->main_context);
-
-  g_warn_if_fail (self->priv->service_proxies->len == 0);
-  g_ptr_array_free (self->priv->service_proxies, TRUE);
-
-  g_warn_if_fail (self->priv->mappings->len == 0);
-  g_ptr_array_free (self->priv->mappings, TRUE);
-
-  G_OBJECT_CLASS (fs_upnp_simple_igd_parent_class)->finalize (object);
-}
-
-static void
-fs_upnp_simple_igd_get_property (GObject *object, guint prop_id,
-    GValue *value, GParamSpec *pspec)
-{
-  FsUpnpSimpleIgd *self = FS_UPNP_SIMPLE_IGD_CAST (object);
-
-  switch (prop_id) {
-    case PROP_REQUEST_TIMEOUT:
-      g_value_set_uint (value, self->priv->request_timeout);
-      break;
-    case PROP_MAIN_CONTEXT:
-      g_value_set_pointer (value, self->priv->main_context);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-
-}
-
-static void
-fs_upnp_simple_igd_set_property (GObject *object, guint prop_id,
-    const GValue *value, GParamSpec *pspec)
-{
-  FsUpnpSimpleIgd *self = FS_UPNP_SIMPLE_IGD_CAST (object);
-
-  switch (prop_id) {
-    case PROP_REQUEST_TIMEOUT:
-      self->priv->request_timeout = g_value_get_uint (value);
-      break;
-    case PROP_MAIN_CONTEXT:
-      if (!self->priv->main_context && g_value_get_pointer (value))
-      {
-        self->priv->main_context = g_value_get_pointer (value);
-        g_main_context_ref (self->priv->main_context);
-      }
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static void
-_cp_service_avail (GUPnPControlPoint *cp,
-    GUPnPServiceProxy *proxy,
-    FsUpnpSimpleIgd *self)
-{
-  struct Proxy *prox = g_slice_new0 (struct Proxy);
-  guint i;
-
-  prox->parent = self;
-  prox->proxy = g_object_ref (proxy);
-  prox->proxymappings = g_ptr_array_new ();
-
-  fs_upnp_simple_igd_gather (self, prox);
-
-  for (i = 0; i < self->priv->mappings->len; i++)
-    fs_upnp_simple_igd_add_proxy_mapping (self, prox,
-        g_ptr_array_index (self->priv->mappings, i));
-
-  g_ptr_array_add(self->priv->service_proxies, prox);
-}
-
-
-static void
-_cp_service_unavail (GUPnPControlPoint *cp,
-    GUPnPServiceProxy *proxy,
-    FsUpnpSimpleIgd *self)
-{
-  guint i;
-
-  for (i=0; i < self->priv->service_proxies->len; i++)
-  {
-    struct Proxy *prox =
-      g_ptr_array_index (self->priv->service_proxies, i);
-
-    if (!strcmp (gupnp_service_info_get_udn (GUPNP_SERVICE_INFO (prox->proxy)),
-            gupnp_service_info_get_udn (GUPNP_SERVICE_INFO (prox->proxy))))
-    {
-      g_ptr_array_foreach (prox->proxymappings, (GFunc) stop_proxymapping,
-          NULL);
-      free_proxy (prox);
-      g_ptr_array_remove_index_fast (self->priv->service_proxies, i);
-      break;
-    }
-  }
-}
-
-
-static void
-fs_upnp_simple_igd_constructed (GObject *object)
-{
-  FsUpnpSimpleIgd *self = FS_UPNP_SIMPLE_IGD_CAST (object);
-
-  if (!self->priv->main_context)
-    self->priv->main_context = g_main_context_ref (g_main_context_default ());
-
-  self->priv->gupnp_context = gupnp_context_new (self->priv->main_context,
-      NULL, 0, NULL);
-  g_return_if_fail (self->priv->gupnp_context);
-
-  self->priv->cp = gupnp_control_point_new (self->priv->gupnp_context,
-      "urn:schemas-upnp-org:service:WANIPConnection:1");
-  g_return_if_fail (self->priv->cp);
-
-  self->priv->avail_handler = g_signal_connect (self->priv->cp,
-      "service-proxy-available",
-      G_CALLBACK (_cp_service_avail), self);
-  self->priv->unavail_handler = g_signal_connect (self->priv->cp,
-      "service-proxy-unavailable",
-      G_CALLBACK (_cp_service_unavail), self);
-
-  gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (self->priv->cp),
-      TRUE);
-
-  if (G_OBJECT_CLASS (fs_upnp_simple_igd_parent_class)->constructed)
-    G_OBJECT_CLASS (fs_upnp_simple_igd_parent_class)->constructed (object);
-}
-
-FsUpnpSimpleIgd *
-fs_upnp_simple_igd_new (GMainContext *main_context)
-{
-  return g_object_new (FS_TYPE_UPNP_SIMPLE_IGD,
-      "main-context", main_context, NULL);
-}
-
-
-static void
-_service_proxy_got_external_ip_address (GUPnPServiceProxy *proxy,
-    GUPnPServiceProxyAction *action,
-    gpointer user_data)
-{
-  struct Proxy *prox = user_data;
-  FsUpnpSimpleIgd *self = prox->parent;
-  GError *error = NULL;
-  gchar *ip = NULL;
-
-  g_return_if_fail (prox->external_ip_action == action);
-
-  prox->external_ip_action = NULL;
-
-  if (gupnp_service_proxy_end_action (proxy, action, &error,
-          "NewExternalIPAddress", G_TYPE_STRING, &ip,
-          NULL))
-  {
-    guint i;
-
-    for (i=0; i < prox->proxymappings->len; i++)
-    {
-      struct ProxyMapping *pm = g_ptr_array_index (prox->proxymappings, i);
-
-      if (pm->mapped)
-        g_signal_emit (self, signals[SIGNAL_MAPPED_EXTERNAL_PORT], 0,
-            pm->mapping->protocol, ip, prox->external_ip,
-            pm->mapping->external_port, pm->mapping->local_ip,
-            pm->mapping->local_port, pm->mapping->description);
-    }
-
-    g_free (prox->external_ip);
-    prox->external_ip = g_strdup (ip);
-
-    g_signal_emit (self, signals[SIGNAL_NEW_EXTERNAL_IP], 0,
-        ip);
-  }
-  else
-  {
-    g_return_if_fail (error);
-    g_signal_emit (self, signals[SIGNAL_ERROR], error->domain,
-        error);
-  }
-  g_clear_error (&error);
-}
-
-static void
-fs_upnp_simple_igd_gather (FsUpnpSimpleIgd *self,
-    struct Proxy *prox)
-{
-  prox->external_ip_action = gupnp_service_proxy_begin_action (prox->proxy,
-      "GetExternalIPAddress",
-      _service_proxy_got_external_ip_address, prox, NULL);
-
-  gupnp_service_proxy_add_notify (prox->proxy, "ExternalIPAddress",
-      G_TYPE_STRING, _external_ip_address_changed, prox);
-
-  gupnp_service_proxy_set_subscribed (prox->proxy, TRUE);
-}
-
-static void
-_service_proxy_renewed_port_mapping (GUPnPServiceProxy *proxy,
-    GUPnPServiceProxyAction *action,
-    gpointer user_data)
-{
-  struct ProxyMapping *pm = user_data;
-  FsUpnpSimpleIgd *self = pm->proxy->parent;
-  GError *error = NULL;
-
-  if (!gupnp_service_proxy_end_action (proxy, action, &error,
-          NULL))
-  {
-    g_return_if_fail (error);
-    g_signal_emit (self, signals[SIGNAL_ERROR_MAPPING_PORT], error->domain,
-        error, pm->mapping->protocol, pm->mapping->external_port,
-        pm->mapping->description);
-  }
-  g_clear_error (&error);
-}
-
-static gboolean
-_renew_mapping_timeout (gpointer user_data)
-{
-  struct ProxyMapping *pm = user_data;
-
-  gupnp_service_proxy_begin_action (pm->proxy->proxy,
-      "AddPortMapping",
-      _service_proxy_renewed_port_mapping, pm,
-      "NewRemoteHost", G_TYPE_STRING, "",
-      "NewExternalPort", G_TYPE_UINT, pm->mapping->external_port,
-      "NewProtocol", G_TYPE_STRING, pm->mapping->protocol,
-      "NewInternalPort", G_TYPE_UINT, pm->mapping->local_port,
-      "NewInternalClient", G_TYPE_STRING, pm->mapping->local_ip,
-      "NewEnabled", G_TYPE_BOOLEAN, TRUE,
-      "NewPortMappingDescription", G_TYPE_STRING, pm->mapping->description,
-      "NewLeaseDuration", G_TYPE_UINT, pm->mapping->lease_duration,
-      NULL);
-
-  return TRUE;
-}
-
-static void
-_service_proxy_added_port_mapping (GUPnPServiceProxy *proxy,
-    GUPnPServiceProxyAction *action,
-    gpointer user_data)
-{
-  struct ProxyMapping *pm = user_data;
-  FsUpnpSimpleIgd *self = pm->proxy->parent;
-  GError *error = NULL;
-
-  g_return_if_fail (pm->action == action);
-
-  pm->action = NULL;
-
-  if (gupnp_service_proxy_end_action (proxy, action, &error,
-          NULL))
-  {
-    pm->mapped = TRUE;
-
-    if (pm->proxy->external_ip)
-      g_signal_emit (self, signals[SIGNAL_MAPPED_EXTERNAL_PORT], 0,
-          pm->mapping->protocol, pm->proxy->external_ip, NULL,
-          pm->mapping->external_port, pm->mapping->local_ip,
-          pm->mapping->local_port, pm->mapping->description);
-
-
-
-    pm->renew_src =
-      g_timeout_source_new_seconds (pm->mapping->lease_duration / 2);
-    g_source_set_callback (pm->renew_src,
-        _renew_mapping_timeout, pm, NULL);
-    g_source_attach (pm->renew_src, self->priv->main_context);
-
-  }
-  else
-  {
-    g_return_if_fail (error);
-    g_signal_emit (self, signals[SIGNAL_ERROR_MAPPING_PORT], error->domain,
-        error, pm->mapping->protocol, pm->mapping->external_port,
-        pm->mapping->description);
-  }
-  g_clear_error (&error);
-
-  stop_proxymapping (pm);
-}
-
-static gboolean
-_service_proxy_add_mapping_timeout (gpointer user_data)
-{
-  struct ProxyMapping *pm = user_data;
-  FsUpnpSimpleIgd *self = pm->proxy->parent;
-
-  stop_proxymapping (pm);
-
-  g_signal_emit (self, signals[SIGNAL_ERROR_MAPPING_PORT], 0,
-      NULL, pm->mapping->protocol, pm->mapping->external_port,
-      pm->mapping->description);
-
-  return FALSE;
-}
-
-static void
-fs_upnp_simple_igd_add_proxy_mapping (FsUpnpSimpleIgd *self, struct Proxy *prox,
-    struct Mapping *mapping)
-{
-  struct ProxyMapping *pm = g_slice_new0 (struct ProxyMapping);
-
-  pm->proxy = prox;
-  pm->mapping = mapping;
-
-  pm->action = gupnp_service_proxy_begin_action (prox->proxy,
-      "AddPortMapping",
-      _service_proxy_added_port_mapping, pm,
-      "NewRemoteHost", G_TYPE_STRING, "",
-      "NewExternalPort", G_TYPE_UINT, mapping->external_port,
-      "NewProtocol", G_TYPE_STRING, mapping->protocol,
-      "NewInternalPort", G_TYPE_UINT, mapping->local_port,
-      "NewInternalClient", G_TYPE_STRING, mapping->local_ip,
-      "NewEnabled", G_TYPE_BOOLEAN, TRUE,
-      "NewPortMappingDescription", G_TYPE_STRING, mapping->description,
-      "NewLeaseDuration", G_TYPE_UINT, mapping->lease_duration,
-      NULL);
-
-  pm->timeout_src =
-    g_timeout_source_new_seconds (self->priv->request_timeout);
-  g_source_set_callback (pm->timeout_src,
-      _service_proxy_add_mapping_timeout, pm, NULL);
-  g_source_attach (pm->timeout_src, self->priv->main_context);
-
-  g_ptr_array_add (prox->proxymappings, pm);
-}
-
-static void
-fs_upnp_simple_igd_add_port_real (FsUpnpSimpleIgd *self,
-    const gchar *protocol,
-    guint16 external_port,
-    const gchar *local_ip,
-    guint16 local_port,
-    guint32 lease_duration,
-    const gchar *description)
-{
-  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->external_port = external_port;
-  mapping->local_ip = g_strdup (local_ip);
-  mapping->local_port = local_port;
-  mapping->lease_duration = lease_duration;
-  mapping->description = g_strdup (description);
-
-  if (!mapping->description)
-    mapping->description = g_strdup ("");
-
-  g_ptr_array_add (self->priv->mappings, mapping);
-
-  for (i=0; i < self->priv->service_proxies->len; i++)
-    fs_upnp_simple_igd_add_proxy_mapping (self,
-        g_ptr_array_index (self->priv->service_proxies, i), mapping);
-}
-
-void
-fs_upnp_simple_igd_add_port (FsUpnpSimpleIgd *self,
-    const gchar *protocol,
-    guint16 external_port,
-    const gchar *local_ip,
-    guint16 local_port,
-    guint32 lease_duration,
-    const gchar *description)
-{
-  FsUpnpSimpleIgdClass *klass = FS_UPNP_SIMPLE_IGD_GET_CLASS (self);
-
-  g_return_if_fail (klass->add_port);
-
-  klass->add_port (self, protocol, external_port, local_ip, local_port,
-      lease_duration, description);
-}
-
-
-static void
-_service_proxy_delete_port_mapping (GUPnPServiceProxy *proxy,
-    GUPnPServiceProxyAction *action,
-    gpointer user_data)
-{
-  GError *error = NULL;
-
-
-  if (!gupnp_service_proxy_end_action (proxy, action, &error,
-          NULL))
-  {
-    g_return_if_fail (error);
-    g_warning ("Error deleting port mapping: %s", error->message);
-  }
-  g_clear_error (&error);
-}
-
-static void
-fs_upnp_simple_igd_remove_port_real (FsUpnpSimpleIgd *self,
-    const gchar *protocol,
-    guint external_port)
-{
-  guint i, j;
-  struct Mapping *mapping;
-
-  g_return_if_fail (protocol);
-
-  for (i = 0; i < self->priv->mappings->len; i++)
-  {
-    struct Mapping *tmpmapping = g_ptr_array_index (self->priv->mappings, i);
-    if (tmpmapping->external_port == external_port &&
-        !strcmp (tmpmapping->protocol, protocol))
-    {
-      mapping = tmpmapping;
-      break;
-    }
-  }
-  g_return_if_fail (mapping);
-
-  g_ptr_array_remove_index_fast (self->priv->mappings, i);
-
-  for (i=0; i < self->priv->service_proxies->len; i++)
-  {
-    struct Proxy *prox = g_ptr_array_index (self->priv->service_proxies, i);
-
-    for (j=0; j < prox->proxymappings->len; j++)
-    {
-      struct ProxyMapping *pm = g_ptr_array_index (prox->proxymappings, j);
-      if (pm->mapping == mapping)
-      {
-        stop_proxymapping (pm);
-
-        if (pm->renew_src)
-          g_source_destroy (pm->renew_src);
-        pm->renew_src = NULL;
-
-        if (pm->mapped)
-          gupnp_service_proxy_begin_action (prox->proxy,
-              "DeletePortMapping",
-              _service_proxy_delete_port_mapping, self,
-              "NewRemoteHost", G_TYPE_STRING, "",
-              "NewExternalPort", G_TYPE_UINT, mapping->external_port,
-              "NewProtocol", G_TYPE_STRING, mapping->protocol,
-              NULL);
-
-        g_slice_free (struct ProxyMapping, pm);
-        g_ptr_array_remove_index_fast (prox->proxymappings, j);
-        j--;
-      }
-    }
-  }
-
-  free_mapping (mapping);
-}
-
-void
-fs_upnp_simple_igd_remove_port (FsUpnpSimpleIgd *self,
-    const gchar *protocol,
-    guint external_port)
-{
-  FsUpnpSimpleIgdClass *klass = FS_UPNP_SIMPLE_IGD_GET_CLASS (self);
-
-  g_return_if_fail (klass->remove_port);
-
-  klass->remove_port (self, protocol, external_port);
-}
-
-static void
-stop_proxymapping (struct ProxyMapping *pm)
-{
-  if (pm->action)
-    gupnp_service_proxy_cancel_action (pm->proxy->proxy,
-        pm->action);
-  pm->action = NULL;
-
-  if (pm->timeout_src)
-    g_source_destroy (pm->timeout_src);
-  pm->timeout_src = NULL;
-}
diff --git a/fs-upnp-simple-igd.h b/fs-upnp-simple-igd.h
deleted file mode 100644
index d0c753e..0000000
--- a/fs-upnp-simple-igd.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Farsight2 - Farsight UPnP IGD abstraction
- *
- * Copyright 2008 Collabora Ltd.
- *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
- * Copyright 2008 Nokia Corp.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef __FS_UPNP_SIMPLE_IGD_H__
-#define __FS_UPNP_SIMPLE_IGD_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-/* TYPE MACROS */
-#define FS_TYPE_UPNP_SIMPLE_IGD       \
-  (fs_upnp_simple_igd_get_type ())
-#define FS_UPNP_SIMPLE_IGD(obj)                               \
-  (G_TYPE_CHECK_INSTANCE_CAST((obj), FS_TYPE_UPNP_SIMPLE_IGD, \
-      FsUpnpSimpleIgd))
-#define FS_UPNP_SIMPLE_IGD_CLASS(klass)                       \
-  (G_TYPE_CHECK_CLASS_CAST((klass), FS_TYPE_UPNP_SIMPLE_IGD,  \
-      FsUpnpSimpleIgdClass))
-#define FS_IS_UPNP_SIMPLE_IGD(obj)                            \
-  (G_TYPE_CHECK_INSTANCE_TYPE((obj), FS_TYPE_UPNP_SIMPLE_IGD))
-#define FS_IS_UPNP_SIMPLE_IGD_CLASS(klass)                    \
-  (G_TYPE_CHECK_CLASS_TYPE((klass), FS_TYPE_UPNP_SIMPLE_IGD))
-#define FS_UPNP_SIMPLE_IGD_GET_CLASS(obj)                     \
-  (G_TYPE_INSTANCE_GET_CLASS ((obj), FS_TYPE_UPNP_SIMPLE_IGD, \
-      FsUpnpSimpleIgdClass))
-#define FS_UPNP_SIMPLE_IGD_CAST(obj)                          \
-  ((FsUpnpSimpleIgd *) (obj))
-
-typedef struct _FsUpnpSimpleIgd FsUpnpSimpleIgd;
-typedef struct _FsUpnpSimpleIgdClass FsUpnpSimpleIgdClass;
-typedef struct _FsUpnpSimpleIgdPrivate FsUpnpSimpleIgdPrivate;
-
-/**
- * FsUpnpSimpleIgdClass:
- * @parent_class: Our parent
- *
- * The Raw UDP component transmitter class
- */
-
-struct _FsUpnpSimpleIgdClass
-{
-  GObjectClass parent_class;
-
-  /*virtual functions */
-
-  void (*add_port) (FsUpnpSimpleIgd *self,
-      const gchar *protocol,
-      guint16 external_port,
-      const gchar *local_ip,
-      guint16 local_port,
-      guint32 lease_duration,
-      const gchar *description);
-
-  void (*remove_port) (FsUpnpSimpleIgd *self,
-      const gchar *protocol,
-      guint external_port);
-
-  /*< private >*/
-};
-
-/**
- * FsUpnpSimpleIgd:
- *
- * All members are private, access them using methods and properties
- */
-struct _FsUpnpSimpleIgd
-{
-  GObject parent;
-
-  /*< private >*/
-  FsUpnpSimpleIgdPrivate *priv;
-};
-
-GType fs_upnp_simple_igd_get_type (void);
-
-FsUpnpSimpleIgd *
-fs_upnp_simple_igd_new (GMainContext *context);
-
-void
-fs_upnp_simple_igd_add_port (FsUpnpSimpleIgd *self,
-    const gchar *protocol,
-    guint16 external_port,
-    const gchar *local_ip,
-    guint16 local_port,
-    guint32 lease_duration,
-    const gchar *description);
-
-void
-fs_upnp_simple_igd_remove_port (FsUpnpSimpleIgd *self,
-    const gchar *protocol,
-    guint external_port);
-
-G_END_DECLS
-
-#endif /* __FS_UPNP_SIMPLE_IGD_H__ */
diff --git a/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd-marshal.list b/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd-marshal.list
new file mode 100644
index 0000000..8b8f99c
--- /dev/null
+++ b/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd-marshal.list
@@ -0,0 +1,2 @@
+VOID:STRING,STRING,STRING,UINT,STRING,UINT,STRING
+VOID:POINTER,STRING,UINT,STRING
diff --git a/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd-thread.c b/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd-thread.c
new file mode 100644
index 0000000..1589639
--- /dev/null
+++ b/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd-thread.c
@@ -0,0 +1,255 @@
+/*
+ * Farsight2 - Farsight UPnP IGD abstraction
+ *
+ * Copyright 2008 Collabora Ltd.
+ *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ * Copyright 2008 Nokia Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+#include "fs-upnp-simple-igd-thread.h"
+
+
+struct _FsUpnpSimpleIgdThreadPrivate
+{
+  GThread *thread;
+  GMainLoop *loop;
+  GMainContext *context;
+  GMutex *mutex;
+};
+
+
+#define FS_UPNP_SIMPLE_IGD_THREAD_GET_PRIVATE(o)                        \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), FS_TYPE_UPNP_SIMPLE_IGD_THREAD,    \
+   FsUpnpSimpleIgdThreadPrivate))
+
+#define FS_UPNP_SIMPLE_IGD_THREAD_LOCK(o)   g_mutex_lock ((o)->priv->mutex)
+#define FS_UPNP_SIMPLE_IGD_THREAD_UNLOCK(o) g_mutex_unlock ((o)->priv->mutex)
+
+
+G_DEFINE_TYPE (FsUpnpSimpleIgdThread, fs_upnp_simple_igd_thread,
+    FS_TYPE_UPNP_SIMPLE_IGD);
+
+static void fs_upnp_simple_igd_thread_constructed (GObject *object);
+static void fs_upnp_simple_igd_thread_dispose (GObject *object);
+static void fs_upnp_simple_igd_thread_finalize (GObject *object);
+
+static void fs_upnp_simple_igd_thread_add_port (FsUpnpSimpleIgd *self,
+    const gchar *protocol,
+    guint16 external_port,
+    const gchar *local_ip,
+    guint16 local_port,
+    guint32 lease_duration,
+    const gchar *description);
+static void fs_upnp_simple_igd_thread_remove_port (FsUpnpSimpleIgd *self,
+    const gchar *protocol,
+    guint external_port);
+
+static void
+fs_upnp_simple_igd_thread_class_init (FsUpnpSimpleIgdThreadClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  FsUpnpSimpleIgdClass *simple_igd_class = FS_UPNP_SIMPLE_IGD_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (FsUpnpSimpleIgdThreadPrivate));
+
+  gobject_class->constructed = fs_upnp_simple_igd_thread_constructed;
+  gobject_class->dispose = fs_upnp_simple_igd_thread_dispose;
+  gobject_class->finalize = fs_upnp_simple_igd_thread_finalize;
+
+  simple_igd_class->add_port = fs_upnp_simple_igd_thread_add_port;
+  simple_igd_class->remove_port = fs_upnp_simple_igd_thread_remove_port;
+}
+
+
+static void
+fs_upnp_simple_igd_thread_init (FsUpnpSimpleIgdThread *self)
+{
+  self->priv = FS_UPNP_SIMPLE_IGD_THREAD_GET_PRIVATE (self);
+
+  self->priv->mutex = g_mutex_new ();
+  self->priv->context = g_main_context_new ();
+
+  g_object_set (self, "main-context", self->priv->context, NULL);
+}
+
+
+static void
+fs_upnp_simple_igd_thread_dispose (GObject *object)
+{
+  FsUpnpSimpleIgdThread *self = FS_UPNP_SIMPLE_IGD_THREAD_CAST (object);
+
+  FS_UPNP_SIMPLE_IGD_THREAD_LOCK (self);
+  if (self->priv->loop)
+    g_main_loop_quit (self->priv->loop);
+  FS_UPNP_SIMPLE_IGD_THREAD_UNLOCK (self);
+
+  g_thread_join (self->priv->thread);
+  self->priv->thread = NULL;
+
+  G_OBJECT_CLASS (fs_upnp_simple_igd_thread_parent_class)->dispose (object);
+}
+
+static void
+fs_upnp_simple_igd_thread_finalize (GObject *object)
+{
+  FsUpnpSimpleIgdThread *self = FS_UPNP_SIMPLE_IGD_THREAD_CAST (object);
+
+  g_main_context_unref (self->priv->context);
+  g_mutex_free (self->priv->mutex);
+
+  G_OBJECT_CLASS (fs_upnp_simple_igd_thread_parent_class)->finalize (object);
+}
+
+static gpointer
+thread_func (gpointer data)
+{
+  FsUpnpSimpleIgdThread *self = data;
+  GMainLoop *loop = g_main_loop_new (self->priv->context, FALSE);
+  FS_UPNP_SIMPLE_IGD_THREAD_LOCK (self);
+  self->priv->loop = loop;
+  FS_UPNP_SIMPLE_IGD_THREAD_UNLOCK (self);
+
+  g_main_loop_run (loop);
+
+  FS_UPNP_SIMPLE_IGD_THREAD_LOCK (self);
+  self->priv->loop = NULL;
+  FS_UPNP_SIMPLE_IGD_THREAD_UNLOCK (self);
+
+  g_main_loop_unref (loop);
+
+  return NULL;
+}
+
+static void
+fs_upnp_simple_igd_thread_constructed (GObject *object)
+{
+  FsUpnpSimpleIgdThread *self = FS_UPNP_SIMPLE_IGD_THREAD_CAST (object);
+
+  if (G_OBJECT_CLASS (fs_upnp_simple_igd_thread_parent_class)->constructed)
+    G_OBJECT_CLASS (fs_upnp_simple_igd_thread_parent_class)->constructed (object);
+
+  self->priv->thread = g_thread_create (thread_func, self, TRUE, NULL);
+  g_return_if_fail (self->priv->thread);
+}
+
+struct AddRemovePortData {
+  FsUpnpSimpleIgd *self;
+  gchar *protocol;
+  guint16 external_port;
+  gchar *local_ip;
+  guint16 local_port;
+  guint32 lease_duration;
+  gchar *description;
+};
+
+static gboolean
+add_port_idle_func (gpointer user_data)
+{
+  struct AddRemovePortData *data = user_data;
+  FsUpnpSimpleIgdClass *klass =
+      FS_UPNP_SIMPLE_IGD_CLASS (fs_upnp_simple_igd_thread_parent_class);
+
+  if (klass->add_port)
+    klass->add_port (data->self, data->protocol, data->external_port,
+        data->local_ip, data->local_port, data->lease_duration,
+        data->description);
+
+  return FALSE;
+}
+
+
+static gboolean
+remove_port_idle_func (gpointer user_data)
+{
+  struct AddRemovePortData *data = user_data;
+  FsUpnpSimpleIgdClass *klass =
+      FS_UPNP_SIMPLE_IGD_CLASS (fs_upnp_simple_igd_thread_parent_class);
+
+  if (klass->remove_port)
+    klass->remove_port (data->self, data->protocol, data->external_port);
+
+  return FALSE;
+}
+
+static void
+free_add_remove_port_data (gpointer user_data)
+{
+  struct AddRemovePortData *data = user_data;
+
+  g_object_unref (data->self);
+  g_free (data->protocol);
+  g_free (data->local_ip);
+  g_free (data->description);
+
+  g_slice_free (struct AddRemovePortData, data);
+}
+
+static void
+fs_upnp_simple_igd_thread_add_port (FsUpnpSimpleIgd *self,
+    const gchar *protocol,
+    guint16 external_port,
+    const gchar *local_ip,
+    guint16 local_port,
+    guint32 lease_duration,
+    const gchar *description)
+{
+  FsUpnpSimpleIgdThread *realself = FS_UPNP_SIMPLE_IGD_THREAD (self);
+  struct AddRemovePortData *data = g_slice_new0 (struct AddRemovePortData);
+  GSource *source;
+
+  data->self = g_object_ref (self);
+  data->protocol = g_strdup (protocol);
+  data->external_port = external_port;
+  data->local_ip = g_strdup (local_ip);
+  data->local_port = local_port;
+  data->lease_duration = lease_duration;
+  data->description = g_strdup (description);
+
+  source = g_idle_source_new ();
+  g_source_set_callback (source, add_port_idle_func, data,
+      free_add_remove_port_data);
+  g_source_attach (source, realself->priv->context);
+  g_main_context_wakeup (realself->priv->context);
+}
+
+static void
+fs_upnp_simple_igd_thread_remove_port (FsUpnpSimpleIgd *self,
+    const gchar *protocol,
+    guint external_port)
+{
+  FsUpnpSimpleIgdThread *realself = FS_UPNP_SIMPLE_IGD_THREAD (self);
+  struct AddRemovePortData *data = g_slice_new0 (struct AddRemovePortData);
+  GSource *source;
+
+  data->self = g_object_ref (self);
+  data->protocol = g_strdup (protocol);
+  data->external_port = external_port;
+
+  source = g_idle_source_new ();
+  g_source_set_callback (source, remove_port_idle_func, data,
+      free_add_remove_port_data);
+  g_source_attach (source, realself->priv->context);
+  g_main_context_wakeup (realself->priv->context);
+}
+
+
+FsUpnpSimpleIgdThread *
+fs_upnp_simple_igd_thread_new ()
+{
+  return g_object_new (FS_TYPE_UPNP_SIMPLE_IGD_THREAD, NULL);
+}
diff --git a/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd-thread.h b/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd-thread.h
new file mode 100644
index 0000000..b3253e4
--- /dev/null
+++ b/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd-thread.h
@@ -0,0 +1,88 @@
+/*
+ * Farsight2 - Farsight UPnP IGD abstraction
+ *
+ * Copyright 2008 Collabora Ltd.
+ *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ * Copyright 2008 Nokia Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef __FS_UPNP_SIMPLE_IGD_THREAD_H__
+#define __FS_UPNP_SIMPLE_IGD_THREAD_H__
+
+#include "fs-upnp-simple-igd.h"
+
+G_BEGIN_DECLS
+
+/* TYPE MACROS */
+#define FS_TYPE_UPNP_SIMPLE_IGD_THREAD       \
+  (fs_upnp_simple_igd_thread_get_type ())
+#define FS_UPNP_SIMPLE_IGD_THREAD(obj)                               \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), FS_TYPE_UPNP_SIMPLE_IGD_THREAD, \
+      FsUpnpSimpleIgdThread))
+#define FS_UPNP_SIMPLE_IGD_THREAD_CLASS(klass)                       \
+  (G_TYPE_CHECK_CLASS_CAST((klass), FS_TYPE_UPNP_SIMPLE_IGD_THREAD,  \
+      FsUpnpSimpleIgdThreadClass))
+#define FS_IS_UPNP_SIMPLE_IGD_THREAD(obj)                            \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), FS_TYPE_UPNP_SIMPLE_IGD_THREAD))
+#define FS_IS_UPNP_SIMPLE_IGD_THREAD_CLASS(klass)                    \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), FS_TYPE_UPNP_SIMPLE_IGD_THREAD))
+#define FS_UPNP_SIMPLE_IGD_THREAD_GET_CLASS(obj)                     \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), FS_TYPE_UPNP_SIMPLE_IGD_THREAD, \
+      FsUpnpSimpleIgdThreadClass))
+#define FS_UPNP_SIMPLE_IGD_THREAD_CAST(obj)                          \
+  ((FsUpnpSimpleIgdThread *) (obj))
+
+typedef struct _FsUpnpSimpleIgdThread FsUpnpSimpleIgdThread;
+typedef struct _FsUpnpSimpleIgdThreadClass FsUpnpSimpleIgdThreadClass;
+typedef struct _FsUpnpSimpleIgdThreadPrivate FsUpnpSimpleIgdThreadPrivate;
+
+/**
+ * FsUpnpSimpleIgdThreadClass:
+ * @parent_class: Our parent
+ *
+ * The Raw UDP component transmitter class
+ */
+
+struct _FsUpnpSimpleIgdThreadClass
+{
+  FsUpnpSimpleIgdClass parent_class;
+
+  /*virtual functions */
+  /*< private >*/
+};
+
+/**
+ * FsUpnpSimpleIgdThread:
+ *
+ * All members are private, access them using methods and properties
+ */
+struct _FsUpnpSimpleIgdThread
+{
+  FsUpnpSimpleIgd parent;
+
+  /*< private >*/
+  FsUpnpSimpleIgdThreadPrivate *priv;
+};
+
+GType fs_upnp_simple_igd_thread_get_type (void);
+
+FsUpnpSimpleIgdThread *
+fs_upnp_simple_igd_thread_new (void);
+
+G_END_DECLS
+
+#endif /* __FS_UPNP_SIMPLE_IGD_THREAD_H__ */
diff --git a/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd.c b/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd.c
new file mode 100644
index 0000000..f342454
--- /dev/null
+++ b/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd.c
@@ -0,0 +1,842 @@
+/*
+ * Farsight2 - Farsight UPnP IGD abstraction
+ *
+ * Copyright 2008 Collabora Ltd.
+ *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ * Copyright 2008 Nokia Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
+#include "fs-upnp-simple-igd.h"
+#include "fs-upnp-simple-igd-marshal.h"
+
+#include <string.h>
+
+#include <libgupnp/gupnp-control-point.h>
+
+
+struct _FsUpnpSimpleIgdPrivate
+{
+  GMainContext *main_context;
+
+  GUPnPContext *gupnp_context;
+  GUPnPControlPoint *cp;
+
+  GPtrArray *service_proxies;
+
+  GPtrArray *mappings;
+
+  gulong avail_handler;
+  gulong unavail_handler;
+
+  guint request_timeout;
+};
+
+struct Proxy {
+  FsUpnpSimpleIgd *parent;
+  GUPnPServiceProxy *proxy;
+
+  gchar *external_ip;
+  GUPnPServiceProxyAction *external_ip_action;
+
+  GPtrArray *proxymappings;
+};
+
+struct Mapping {
+  gchar *protocol;
+  guint external_port;
+  gchar *local_ip;
+  guint16 local_port;
+  guint32 lease_duration;
+  gchar *description;
+};
+
+struct ProxyMapping {
+  struct Proxy *proxy;
+  struct Mapping *mapping;
+
+  GUPnPServiceProxyAction *action;
+  GSource *timeout_src;
+
+  gboolean mapped;
+
+  GSource *renew_src;
+};
+
+/* signals */
+enum
+{
+  SIGNAL_NEW_EXTERNAL_IP,
+  SIGNAL_MAPPED_EXTERNAL_PORT,
+  SIGNAL_ERROR_MAPPING_PORT,
+  SIGNAL_ERROR,
+  LAST_SIGNAL
+};
+
+/* props */
+enum
+{
+  PROP_0,
+  PROP_REQUEST_TIMEOUT,
+  PROP_MAIN_CONTEXT
+};
+
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+
+#define FS_UPNP_SIMPLE_IGD_GET_PRIVATE(o)                                 \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), FS_TYPE_UPNP_SIMPLE_IGD,             \
+   FsUpnpSimpleIgdPrivate))
+
+
+G_DEFINE_TYPE (FsUpnpSimpleIgd, fs_upnp_simple_igd, G_TYPE_OBJECT);
+
+
+static void fs_upnp_simple_igd_constructed (GObject *object);
+static void fs_upnp_simple_igd_dispose (GObject *object);
+static void fs_upnp_simple_igd_finalize (GObject *object);
+static void fs_upnp_simple_igd_get_property (GObject *object, guint prop_id,
+    GValue *value, GParamSpec *pspec);
+static void fs_upnp_simple_igd_set_property (GObject *object, guint prop_id,
+    const GValue *value, GParamSpec *pspec);
+
+static void fs_upnp_simple_igd_gather (FsUpnpSimpleIgd *self,
+    struct Proxy *prox);
+static void fs_upnp_simple_igd_add_proxy_mapping (FsUpnpSimpleIgd *self,
+    struct Proxy *prox,
+    struct Mapping *mapping);
+
+static void free_proxy (struct Proxy *prox);
+static void free_mapping (struct Mapping *mapping);
+
+static void stop_proxymapping (struct ProxyMapping *pm);
+
+static void fs_upnp_simple_igd_add_port_real (FsUpnpSimpleIgd *self,
+    const gchar *protocol,
+    guint16 external_port,
+    const gchar *local_ip,
+    guint16 local_port,
+    guint32 lease_duration,
+    const gchar *description);
+static void fs_upnp_simple_igd_remove_port_real (FsUpnpSimpleIgd *self,
+    const gchar *protocol,
+    guint external_port);
+
+
+static void
+fs_upnp_simple_igd_class_init (FsUpnpSimpleIgdClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (FsUpnpSimpleIgdPrivate));
+
+  gobject_class->constructed = fs_upnp_simple_igd_constructed;
+  gobject_class->dispose = fs_upnp_simple_igd_dispose;
+  gobject_class->finalize = fs_upnp_simple_igd_finalize;
+  gobject_class->set_property = fs_upnp_simple_igd_set_property;
+  gobject_class->get_property = fs_upnp_simple_igd_get_property;
+
+  klass->add_port = fs_upnp_simple_igd_add_port_real;
+  klass->remove_port = fs_upnp_simple_igd_remove_port_real;
+
+  g_object_class_install_property (gobject_class,
+      PROP_REQUEST_TIMEOUT,
+      g_param_spec_uint ("request-timeout",
+          "The timeout after which a request is considered to have failed",
+          "After this timeout, the request is considered to have failed and"
+          "is dropped (in seconds).",
+          0, G_MAXUINT, 5,
+          G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+      PROP_MAIN_CONTEXT,
+      g_param_spec_pointer ("main-context",
+          "The GMainContext to use",
+          "This GMainContext will be used for all async activities",
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+   /**
+   * FsUpnpSimpleIgd::new-external-ip
+   * @self: #FsUpnpSimpleIgd that emitted the signal
+   * @ip: The string representing the new external IP
+   *
+   * This signal means that a new external IP has been found on an IGD.
+   *
+   */
+  signals[SIGNAL_NEW_EXTERNAL_IP] = g_signal_new ("new-external-ip",
+      G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST,
+      0,
+      NULL,
+      NULL,
+      g_cclosure_marshal_VOID__STRING,
+      G_TYPE_NONE, 1, G_TYPE_STRING);
+
+
+  /**
+   * FsUpnpSimpleIgd::mapped-external-port
+   * @self: #FsUpnpSimpleIgd that emitted the signal
+   * @proto: the requested protocol ("UDP" or "TCP")
+   * @external_ip: the external IP
+   * @replaces_external_ip: if this mapping replaces another mapping,
+   *  this is the old external IP
+   * @external_port: the external port
+   * @local_ip: internal ip this is forwarded to
+   * @local_port: the local port
+   * @description: the user's selected description
+   * @ip: The string representing the new external IP
+   *
+   * This signal means that an IGD has been found that that adding a port
+   * mapping has succeeded.
+   *
+   */
+  signals[SIGNAL_MAPPED_EXTERNAL_PORT] = g_signal_new ("mapped-external-port",
+      G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST,
+      0,
+      NULL,
+      NULL,
+      _fs_upnp_simple_igd_marshal_VOID__STRING_STRING_STRING_UINT_STRING_UINT_STRING,
+      G_TYPE_NONE, 7, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT,
+      G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING);
+
+  /**
+   * FsUpnpSimpleIgd::error-mapping-port
+   * @self: #FsUpnpSimpleIgd that emitted the signal
+   * @error: a #GError or %NULL if its a timeout
+   * @proto: The requested protocol
+   * @external_port: the requested external port
+   * @description: the passed description
+   *
+   * This means that mapping a port on a specific IGD has failed (it may still
+   * succeed on other IGDs on the network).
+   */
+  signals[SIGNAL_ERROR_MAPPING_PORT] = g_signal_new ("error-mapping-port",
+      G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+      0,
+      NULL,
+      NULL,
+      _fs_upnp_simple_igd_marshal_VOID__POINTER_STRING_UINT_STRING,
+      G_TYPE_NONE, 4, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_UINT,
+      G_TYPE_STRING);
+
+  /**
+   * FsUpnpSimpleIgd::error
+   * @self: #FsUpnpSimpleIgd that emitted the signal
+   * @error: a #GError
+   *
+   * This means that an asynchronous error has happened.
+   *
+   */
+  signals[SIGNAL_ERROR] = g_signal_new ("error",
+      G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+      0,
+      NULL,
+      NULL,
+      g_cclosure_marshal_VOID__POINTER,
+      G_TYPE_NONE, 1, G_TYPE_POINTER);
+}
+
+static void
+fs_upnp_simple_igd_init (FsUpnpSimpleIgd *self)
+{
+  self->priv = FS_UPNP_SIMPLE_IGD_GET_PRIVATE (self);
+
+  self->priv->request_timeout = 5;
+
+  self->priv->service_proxies = g_ptr_array_new ();
+  self->priv->mappings = g_ptr_array_new ();
+}
+
+static void
+fs_upnp_simple_igd_dispose (GObject *object)
+{
+  FsUpnpSimpleIgd *self = FS_UPNP_SIMPLE_IGD_CAST (object);
+
+  if (self->priv->avail_handler)
+    g_signal_handler_disconnect (self->priv->cp, self->priv->avail_handler);
+  self->priv->avail_handler = 0;
+
+  if (self->priv->unavail_handler)
+    g_signal_handler_disconnect (self->priv->cp, self->priv->unavail_handler);
+  self->priv->unavail_handler = 0;
+
+  while (self->priv->mappings->len)
+  {
+    free_mapping (
+        g_ptr_array_index (self->priv->mappings, 0));
+    g_ptr_array_remove_index_fast (self->priv->mappings, 0);
+  }
+
+  while (self->priv->service_proxies->len)
+  {
+    free_proxy (
+        g_ptr_array_index (self->priv->service_proxies, 0));
+    g_ptr_array_remove_index_fast (self->priv->service_proxies, 0);
+  }
+
+  if (self->priv->cp)
+    g_object_unref (self->priv->cp);
+  self->priv->cp = NULL;
+
+  if (self->priv->gupnp_context)
+    g_object_unref (self->priv->gupnp_context);
+  self->priv->gupnp_context = NULL;
+
+  G_OBJECT_CLASS (fs_upnp_simple_igd_parent_class)->dispose (object);
+}
+
+
+static void
+_external_ip_address_changed (GUPnPServiceProxy *proxy, const gchar *variable,
+    GValue *value, gpointer user_data)
+{
+  struct Proxy *prox = user_data;
+  gchar *new_ip;
+  guint i;
+
+  g_return_if_fail (G_VALUE_HOLDS_STRING(value));
+
+  new_ip = g_value_dup_string (value);
+
+  for (i=0; i < prox->proxymappings->len; i++)
+  {
+    struct ProxyMapping *pm = g_ptr_array_index (prox->proxymappings, i);
+
+    if (pm->mapped)
+      g_signal_emit (prox->parent, signals[SIGNAL_MAPPED_EXTERNAL_PORT], 0,
+          pm->mapping->protocol, new_ip, prox->external_ip,
+          pm->mapping->external_port, pm->mapping->local_ip,
+          pm->mapping->local_port, pm->mapping->description);
+  }
+
+  g_free (prox->external_ip);
+  prox->external_ip = new_ip;
+}
+
+static void
+free_proxy (struct Proxy *prox)
+{
+  if (prox->external_ip_action)
+    gupnp_service_proxy_cancel_action (prox->proxy, prox->external_ip_action);
+
+  gupnp_service_proxy_remove_notify (prox->proxy, "ExternalIPAddress",
+      _external_ip_address_changed, prox);
+
+  g_object_unref (prox->proxy);
+  g_ptr_array_foreach (prox->proxymappings, (GFunc) stop_proxymapping, NULL);
+  g_ptr_array_free (prox->proxymappings, TRUE);
+  g_slice_free (struct Proxy, prox);
+}
+
+static void
+free_mapping (struct Mapping *mapping)
+{
+  g_free (mapping->protocol);
+  g_free (mapping->local_ip);
+  g_free (mapping->description);
+  g_slice_free (struct Mapping, mapping);
+}
+
+static void
+fs_upnp_simple_igd_finalize (GObject *object)
+{
+  FsUpnpSimpleIgd *self = FS_UPNP_SIMPLE_IGD_CAST (object);
+
+  g_main_context_unref (self->priv->main_context);
+
+  g_warn_if_fail (self->priv->service_proxies->len == 0);
+  g_ptr_array_free (self->priv->service_proxies, TRUE);
+
+  g_warn_if_fail (self->priv->mappings->len == 0);
+  g_ptr_array_free (self->priv->mappings, TRUE);
+
+  G_OBJECT_CLASS (fs_upnp_simple_igd_parent_class)->finalize (object);
+}
+
+static void
+fs_upnp_simple_igd_get_property (GObject *object, guint prop_id,
+    GValue *value, GParamSpec *pspec)
+{
+  FsUpnpSimpleIgd *self = FS_UPNP_SIMPLE_IGD_CAST (object);
+
+  switch (prop_id) {
+    case PROP_REQUEST_TIMEOUT:
+      g_value_set_uint (value, self->priv->request_timeout);
+      break;
+    case PROP_MAIN_CONTEXT:
+      g_value_set_pointer (value, self->priv->main_context);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+}
+
+static void
+fs_upnp_simple_igd_set_property (GObject *object, guint prop_id,
+    const GValue *value, GParamSpec *pspec)
+{
+  FsUpnpSimpleIgd *self = FS_UPNP_SIMPLE_IGD_CAST (object);
+
+  switch (prop_id) {
+    case PROP_REQUEST_TIMEOUT:
+      self->priv->request_timeout = g_value_get_uint (value);
+      break;
+    case PROP_MAIN_CONTEXT:
+      if (!self->priv->main_context && g_value_get_pointer (value))
+      {
+        self->priv->main_context = g_value_get_pointer (value);
+        g_main_context_ref (self->priv->main_context);
+      }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+_cp_service_avail (GUPnPControlPoint *cp,
+    GUPnPServiceProxy *proxy,
+    FsUpnpSimpleIgd *self)
+{
+  struct Proxy *prox = g_slice_new0 (struct Proxy);
+  guint i;
+
+  prox->parent = self;
+  prox->proxy = g_object_ref (proxy);
+  prox->proxymappings = g_ptr_array_new ();
+
+  fs_upnp_simple_igd_gather (self, prox);
+
+  for (i = 0; i < self->priv->mappings->len; i++)
+    fs_upnp_simple_igd_add_proxy_mapping (self, prox,
+        g_ptr_array_index (self->priv->mappings, i));
+
+  g_ptr_array_add(self->priv->service_proxies, prox);
+}
+
+
+static void
+_cp_service_unavail (GUPnPControlPoint *cp,
+    GUPnPServiceProxy *proxy,
+    FsUpnpSimpleIgd *self)
+{
+  guint i;
+
+  for (i=0; i < self->priv->service_proxies->len; i++)
+  {
+    struct Proxy *prox =
+      g_ptr_array_index (self->priv->service_proxies, i);
+
+    if (!strcmp (gupnp_service_info_get_udn (GUPNP_SERVICE_INFO (prox->proxy)),
+            gupnp_service_info_get_udn (GUPNP_SERVICE_INFO (prox->proxy))))
+    {
+      g_ptr_array_foreach (prox->proxymappings, (GFunc) stop_proxymapping,
+          NULL);
+      free_proxy (prox);
+      g_ptr_array_remove_index_fast (self->priv->service_proxies, i);
+      break;
+    }
+  }
+}
+
+
+static void
+fs_upnp_simple_igd_constructed (GObject *object)
+{
+  FsUpnpSimpleIgd *self = FS_UPNP_SIMPLE_IGD_CAST (object);
+
+  if (!self->priv->main_context)
+    self->priv->main_context = g_main_context_ref (g_main_context_default ());
+
+  self->priv->gupnp_context = gupnp_context_new (self->priv->main_context,
+      NULL, 0, NULL);
+  g_return_if_fail (self->priv->gupnp_context);
+
+  self->priv->cp = gupnp_control_point_new (self->priv->gupnp_context,
+      "urn:schemas-upnp-org:service:WANIPConnection:1");
+  g_return_if_fail (self->priv->cp);
+
+  self->priv->avail_handler = g_signal_connect (self->priv->cp,
+      "service-proxy-available",
+      G_CALLBACK (_cp_service_avail), self);
+  self->priv->unavail_handler = g_signal_connect (self->priv->cp,
+      "service-proxy-unavailable",
+      G_CALLBACK (_cp_service_unavail), self);
+
+  gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (self->priv->cp),
+      TRUE);
+
+  if (G_OBJECT_CLASS (fs_upnp_simple_igd_parent_class)->constructed)
+    G_OBJECT_CLASS (fs_upnp_simple_igd_parent_class)->constructed (object);
+}
+
+FsUpnpSimpleIgd *
+fs_upnp_simple_igd_new (GMainContext *main_context)
+{
+  return g_object_new (FS_TYPE_UPNP_SIMPLE_IGD,
+      "main-context", main_context, NULL);
+}
+
+
+static void
+_service_proxy_got_external_ip_address (GUPnPServiceProxy *proxy,
+    GUPnPServiceProxyAction *action,
+    gpointer user_data)
+{
+  struct Proxy *prox = user_data;
+  FsUpnpSimpleIgd *self = prox->parent;
+  GError *error = NULL;
+  gchar *ip = NULL;
+
+  g_return_if_fail (prox->external_ip_action == action);
+
+  prox->external_ip_action = NULL;
+
+  if (gupnp_service_proxy_end_action (proxy, action, &error,
+          "NewExternalIPAddress", G_TYPE_STRING, &ip,
+          NULL))
+  {
+    guint i;
+
+    for (i=0; i < prox->proxymappings->len; i++)
+    {
+      struct ProxyMapping *pm = g_ptr_array_index (prox->proxymappings, i);
+
+      if (pm->mapped)
+        g_signal_emit (self, signals[SIGNAL_MAPPED_EXTERNAL_PORT], 0,
+            pm->mapping->protocol, ip, prox->external_ip,
+            pm->mapping->external_port, pm->mapping->local_ip,
+            pm->mapping->local_port, pm->mapping->description);
+    }
+
+    g_free (prox->external_ip);
+    prox->external_ip = g_strdup (ip);
+
+    g_signal_emit (self, signals[SIGNAL_NEW_EXTERNAL_IP], 0,
+        ip);
+  }
+  else
+  {
+    g_return_if_fail (error);
+    g_signal_emit (self, signals[SIGNAL_ERROR], error->domain,
+        error);
+  }
+  g_clear_error (&error);
+}
+
+static void
+fs_upnp_simple_igd_gather (FsUpnpSimpleIgd *self,
+    struct Proxy *prox)
+{
+  prox->external_ip_action = gupnp_service_proxy_begin_action (prox->proxy,
+      "GetExternalIPAddress",
+      _service_proxy_got_external_ip_address, prox, NULL);
+
+  gupnp_service_proxy_add_notify (prox->proxy, "ExternalIPAddress",
+      G_TYPE_STRING, _external_ip_address_changed, prox);
+
+  gupnp_service_proxy_set_subscribed (prox->proxy, TRUE);
+}
+
+static void
+_service_proxy_renewed_port_mapping (GUPnPServiceProxy *proxy,
+    GUPnPServiceProxyAction *action,
+    gpointer user_data)
+{
+  struct ProxyMapping *pm = user_data;
+  FsUpnpSimpleIgd *self = pm->proxy->parent;
+  GError *error = NULL;
+
+  if (!gupnp_service_proxy_end_action (proxy, action, &error,
+          NULL))
+  {
+    g_return_if_fail (error);
+    g_signal_emit (self, signals[SIGNAL_ERROR_MAPPING_PORT], error->domain,
+        error, pm->mapping->protocol, pm->mapping->external_port,
+        pm->mapping->description);
+  }
+  g_clear_error (&error);
+}
+
+static gboolean
+_renew_mapping_timeout (gpointer user_data)
+{
+  struct ProxyMapping *pm = user_data;
+
+  gupnp_service_proxy_begin_action (pm->proxy->proxy,
+      "AddPortMapping",
+      _service_proxy_renewed_port_mapping, pm,
+      "NewRemoteHost", G_TYPE_STRING, "",
+      "NewExternalPort", G_TYPE_UINT, pm->mapping->external_port,
+      "NewProtocol", G_TYPE_STRING, pm->mapping->protocol,
+      "NewInternalPort", G_TYPE_UINT, pm->mapping->local_port,
+      "NewInternalClient", G_TYPE_STRING, pm->mapping->local_ip,
+      "NewEnabled", G_TYPE_BOOLEAN, TRUE,
+      "NewPortMappingDescription", G_TYPE_STRING, pm->mapping->description,
+      "NewLeaseDuration", G_TYPE_UINT, pm->mapping->lease_duration,
+      NULL);
+
+  return TRUE;
+}
+
+static void
+_service_proxy_added_port_mapping (GUPnPServiceProxy *proxy,
+    GUPnPServiceProxyAction *action,
+    gpointer user_data)
+{
+  struct ProxyMapping *pm = user_data;
+  FsUpnpSimpleIgd *self = pm->proxy->parent;
+  GError *error = NULL;
+
+  g_return_if_fail (pm->action == action);
+
+  pm->action = NULL;
+
+  if (gupnp_service_proxy_end_action (proxy, action, &error,
+          NULL))
+  {
+    pm->mapped = TRUE;
+
+    if (pm->proxy->external_ip)
+      g_signal_emit (self, signals[SIGNAL_MAPPED_EXTERNAL_PORT], 0,
+          pm->mapping->protocol, pm->proxy->external_ip, NULL,
+          pm->mapping->external_port, pm->mapping->local_ip,
+          pm->mapping->local_port, pm->mapping->description);
+
+
+
+    pm->renew_src =
+      g_timeout_source_new_seconds (pm->mapping->lease_duration / 2);
+    g_source_set_callback (pm->renew_src,
+        _renew_mapping_timeout, pm, NULL);
+    g_source_attach (pm->renew_src, self->priv->main_context);
+
+  }
+  else
+  {
+    g_return_if_fail (error);
+    g_signal_emit (self, signals[SIGNAL_ERROR_MAPPING_PORT], error->domain,
+        error, pm->mapping->protocol, pm->mapping->external_port,
+        pm->mapping->description);
+  }
+  g_clear_error (&error);
+
+  stop_proxymapping (pm);
+}
+
+static gboolean
+_service_proxy_add_mapping_timeout (gpointer user_data)
+{
+  struct ProxyMapping *pm = user_data;
+  FsUpnpSimpleIgd *self = pm->proxy->parent;
+
+  stop_proxymapping (pm);
+
+  g_signal_emit (self, signals[SIGNAL_ERROR_MAPPING_PORT], 0,
+      NULL, pm->mapping->protocol, pm->mapping->external_port,
+      pm->mapping->description);
+
+  return FALSE;
+}
+
+static void
+fs_upnp_simple_igd_add_proxy_mapping (FsUpnpSimpleIgd *self, struct Proxy *prox,
+    struct Mapping *mapping)
+{
+  struct ProxyMapping *pm = g_slice_new0 (struct ProxyMapping);
+
+  pm->proxy = prox;
+  pm->mapping = mapping;
+
+  pm->action = gupnp_service_proxy_begin_action (prox->proxy,
+      "AddPortMapping",
+      _service_proxy_added_port_mapping, pm,
+      "NewRemoteHost", G_TYPE_STRING, "",
+      "NewExternalPort", G_TYPE_UINT, mapping->external_port,
+      "NewProtocol", G_TYPE_STRING, mapping->protocol,
+      "NewInternalPort", G_TYPE_UINT, mapping->local_port,
+      "NewInternalClient", G_TYPE_STRING, mapping->local_ip,
+      "NewEnabled", G_TYPE_BOOLEAN, TRUE,
+      "NewPortMappingDescription", G_TYPE_STRING, mapping->description,
+      "NewLeaseDuration", G_TYPE_UINT, mapping->lease_duration,
+      NULL);
+
+  pm->timeout_src =
+    g_timeout_source_new_seconds (self->priv->request_timeout);
+  g_source_set_callback (pm->timeout_src,
+      _service_proxy_add_mapping_timeout, pm, NULL);
+  g_source_attach (pm->timeout_src, self->priv->main_context);
+
+  g_ptr_array_add (prox->proxymappings, pm);
+}
+
+static void
+fs_upnp_simple_igd_add_port_real (FsUpnpSimpleIgd *self,
+    const gchar *protocol,
+    guint16 external_port,
+    const gchar *local_ip,
+    guint16 local_port,
+    guint32 lease_duration,
+    const gchar *description)
+{
+  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->external_port = external_port;
+  mapping->local_ip = g_strdup (local_ip);
+  mapping->local_port = local_port;
+  mapping->lease_duration = lease_duration;
+  mapping->description = g_strdup (description);
+
+  if (!mapping->description)
+    mapping->description = g_strdup ("");
+
+  g_ptr_array_add (self->priv->mappings, mapping);
+
+  for (i=0; i < self->priv->service_proxies->len; i++)
+    fs_upnp_simple_igd_add_proxy_mapping (self,
+        g_ptr_array_index (self->priv->service_proxies, i), mapping);
+}
+
+void
+fs_upnp_simple_igd_add_port (FsUpnpSimpleIgd *self,
+    const gchar *protocol,
+    guint16 external_port,
+    const gchar *local_ip,
+    guint16 local_port,
+    guint32 lease_duration,
+    const gchar *description)
+{
+  FsUpnpSimpleIgdClass *klass = FS_UPNP_SIMPLE_IGD_GET_CLASS (self);
+
+  g_return_if_fail (klass->add_port);
+
+  klass->add_port (self, protocol, external_port, local_ip, local_port,
+      lease_duration, description);
+}
+
+
+static void
+_service_proxy_delete_port_mapping (GUPnPServiceProxy *proxy,
+    GUPnPServiceProxyAction *action,
+    gpointer user_data)
+{
+  GError *error = NULL;
+
+
+  if (!gupnp_service_proxy_end_action (proxy, action, &error,
+          NULL))
+  {
+    g_return_if_fail (error);
+    g_warning ("Error deleting port mapping: %s", error->message);
+  }
+  g_clear_error (&error);
+}
+
+static void
+fs_upnp_simple_igd_remove_port_real (FsUpnpSimpleIgd *self,
+    const gchar *protocol,
+    guint external_port)
+{
+  guint i, j;
+  struct Mapping *mapping;
+
+  g_return_if_fail (protocol);
+
+  for (i = 0; i < self->priv->mappings->len; i++)
+  {
+    struct Mapping *tmpmapping = g_ptr_array_index (self->priv->mappings, i);
+    if (tmpmapping->external_port == external_port &&
+        !strcmp (tmpmapping->protocol, protocol))
+    {
+      mapping = tmpmapping;
+      break;
+    }
+  }
+  g_return_if_fail (mapping);
+
+  g_ptr_array_remove_index_fast (self->priv->mappings, i);
+
+  for (i=0; i < self->priv->service_proxies->len; i++)
+  {
+    struct Proxy *prox = g_ptr_array_index (self->priv->service_proxies, i);
+
+    for (j=0; j < prox->proxymappings->len; j++)
+    {
+      struct ProxyMapping *pm = g_ptr_array_index (prox->proxymappings, j);
+      if (pm->mapping == mapping)
+      {
+        stop_proxymapping (pm);
+
+        if (pm->renew_src)
+          g_source_destroy (pm->renew_src);
+        pm->renew_src = NULL;
+
+        if (pm->mapped)
+          gupnp_service_proxy_begin_action (prox->proxy,
+              "DeletePortMapping",
+              _service_proxy_delete_port_mapping, self,
+              "NewRemoteHost", G_TYPE_STRING, "",
+              "NewExternalPort", G_TYPE_UINT, mapping->external_port,
+              "NewProtocol", G_TYPE_STRING, mapping->protocol,
+              NULL);
+
+        g_slice_free (struct ProxyMapping, pm);
+        g_ptr_array_remove_index_fast (prox->proxymappings, j);
+        j--;
+      }
+    }
+  }
+
+  free_mapping (mapping);
+}
+
+void
+fs_upnp_simple_igd_remove_port (FsUpnpSimpleIgd *self,
+    const gchar *protocol,
+    guint external_port)
+{
+  FsUpnpSimpleIgdClass *klass = FS_UPNP_SIMPLE_IGD_GET_CLASS (self);
+
+  g_return_if_fail (klass->remove_port);
+
+  klass->remove_port (self, protocol, external_port);
+}
+
+static void
+stop_proxymapping (struct ProxyMapping *pm)
+{
+  if (pm->action)
+    gupnp_service_proxy_cancel_action (pm->proxy->proxy,
+        pm->action);
+  pm->action = NULL;
+
+  if (pm->timeout_src)
+    g_source_destroy (pm->timeout_src);
+  pm->timeout_src = NULL;
+}
diff --git a/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd.h b/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd.h
new file mode 100644
index 0000000..d0c753e
--- /dev/null
+++ b/gst-libs/ext/fssimpleupnp/fs-upnp-simple-igd.h
@@ -0,0 +1,116 @@
+/*
+ * Farsight2 - Farsight UPnP IGD abstraction
+ *
+ * Copyright 2008 Collabora Ltd.
+ *  @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ * Copyright 2008 Nokia Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef __FS_UPNP_SIMPLE_IGD_H__
+#define __FS_UPNP_SIMPLE_IGD_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* TYPE MACROS */
+#define FS_TYPE_UPNP_SIMPLE_IGD       \
+  (fs_upnp_simple_igd_get_type ())
+#define FS_UPNP_SIMPLE_IGD(obj)                               \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), FS_TYPE_UPNP_SIMPLE_IGD, \
+      FsUpnpSimpleIgd))
+#define FS_UPNP_SIMPLE_IGD_CLASS(klass)                       \
+  (G_TYPE_CHECK_CLASS_CAST((klass), FS_TYPE_UPNP_SIMPLE_IGD,  \
+      FsUpnpSimpleIgdClass))
+#define FS_IS_UPNP_SIMPLE_IGD(obj)                            \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), FS_TYPE_UPNP_SIMPLE_IGD))
+#define FS_IS_UPNP_SIMPLE_IGD_CLASS(klass)                    \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), FS_TYPE_UPNP_SIMPLE_IGD))
+#define FS_UPNP_SIMPLE_IGD_GET_CLASS(obj)                     \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), FS_TYPE_UPNP_SIMPLE_IGD, \
+      FsUpnpSimpleIgdClass))
+#define FS_UPNP_SIMPLE_IGD_CAST(obj)                          \
+  ((FsUpnpSimpleIgd *) (obj))
+
+typedef struct _FsUpnpSimpleIgd FsUpnpSimpleIgd;
+typedef struct _FsUpnpSimpleIgdClass FsUpnpSimpleIgdClass;
+typedef struct _FsUpnpSimpleIgdPrivate FsUpnpSimpleIgdPrivate;
+
+/**
+ * FsUpnpSimpleIgdClass:
+ * @parent_class: Our parent
+ *
+ * The Raw UDP component transmitter class
+ */
+
+struct _FsUpnpSimpleIgdClass
+{
+  GObjectClass parent_class;
+
+  /*virtual functions */
+
+  void (*add_port) (FsUpnpSimpleIgd *self,
+      const gchar *protocol,
+      guint16 external_port,
+      const gchar *local_ip,
+      guint16 local_port,
+      guint32 lease_duration,
+      const gchar *description);
+
+  void (*remove_port) (FsUpnpSimpleIgd *self,
+      const gchar *protocol,
+      guint external_port);
+
+  /*< private >*/
+};
+
+/**
+ * FsUpnpSimpleIgd:
+ *
+ * All members are private, access them using methods and properties
+ */
+struct _FsUpnpSimpleIgd
+{
+  GObject parent;
+
+  /*< private >*/
+  FsUpnpSimpleIgdPrivate *priv;
+};
+
+GType fs_upnp_simple_igd_get_type (void);
+
+FsUpnpSimpleIgd *
+fs_upnp_simple_igd_new (GMainContext *context);
+
+void
+fs_upnp_simple_igd_add_port (FsUpnpSimpleIgd *self,
+    const gchar *protocol,
+    guint16 external_port,
+    const gchar *local_ip,
+    guint16 local_port,
+    guint32 lease_duration,
+    const gchar *description);
+
+void
+fs_upnp_simple_igd_remove_port (FsUpnpSimpleIgd *self,
+    const gchar *protocol,
+    guint external_port);
+
+G_END_DECLS
+
+#endif /* __FS_UPNP_SIMPLE_IGD_H__ */
diff --git a/test-thread.c b/test-thread.c
deleted file mode 100644
index 546f46b..0000000
--- a/test-thread.c
+++ /dev/null
@@ -1,85 +0,0 @@
-
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <glib.h>
-
-#include "fs-upnp-simple-igd-thread.h"
-
-static void
-_mapped_external_port (FsUpnpSimpleIgd *igd, gchar *proto,
-    gchar *external_ip, gchar *replaces_external_ip, guint external_port,
-    gchar *local_ip, guint local_port,
-    gchar *description, gpointer user_data)
-{
-  g_debug ("proto:%s ex:%s oldex:%s exp:%u local:%s localp:%u desc:%s",
-      proto, external_ip, replaces_external_ip, external_port, local_ip,
-      local_port, description);
-
-}
-
-
-
-static void
-_error_mapping_external_port (FsUpnpSimpleIgd *igd, GError *error,
-    gchar *proto, guint external_port,
-    gchar *description, gpointer user_data)
-{
-  g_error ("proto:%s port:%u desc:%s error: %s", proto, external_port,
-      description, error->message);
-}
-
-
-static void
-_error (FsUpnpSimpleIgd *igd, GError *error, gpointer user_data)
-{
-  g_error ("error: %s", error->message);
-}
-
-int
-main (int argc, char **argv)
-{
-  FsUpnpSimpleIgdThread *igd = NULL;
-  guint external_port, internal_port;
-
-
-  if (argc != 5)
-  {
-    g_print ("Usage: %s <external port> <local ip> <local port> <description>\n",
-        argv[0]);
-    return 0;
-  }
-
-  external_port = atoi (argv[1]);
-  internal_port = atoi (argv[3]);
-  g_return_val_if_fail (external_port && internal_port, 1);
-
-  g_type_init ();
-  g_thread_init (NULL);
-
-  igd = fs_upnp_simple_igd_thread_new ();
-
-  g_signal_connect (igd, "mapped-external-port",
-      G_CALLBACK (_mapped_external_port),
-      NULL);
-  g_signal_connect (igd, "error", G_CALLBACK (_error),
-      NULL);
-  g_signal_connect (igd, "error-mapping-port",
-      G_CALLBACK (_error_mapping_external_port),
-      NULL);
-
-  fs_upnp_simple_igd_add_port (FS_UPNP_SIMPLE_IGD (igd),
-      "TCP", external_port, argv[2],
-      internal_port, 20, argv[4]);
-
-  sleep (30);
-
-  fs_upnp_simple_igd_remove_port (FS_UPNP_SIMPLE_IGD (igd), "TCP",
-      external_port);
-
-  sleep (5);
-
-  g_object_unref (igd);
-
-  return 0;
-}
diff --git a/test.c b/test.c
deleted file mode 100644
index 19d58c0..0000000
--- a/test.c
+++ /dev/null
@@ -1,98 +0,0 @@
-
-#include <stdlib.h>
-
-#include <glib.h>
-
-#include "fs-upnp-simple-igd.h"
-
-GMainContext *ctx = NULL;
-GMainLoop *loop = NULL;
-FsUpnpSimpleIgd *igd = NULL;
-guint external_port, internal_port;
-
-static gboolean
-_remove_port (gpointer user_data)
-{
-  g_debug ("removing port");
-  fs_upnp_simple_igd_remove_port (igd, "TCP", external_port);
-
-  return FALSE;
-}
-
-static void
-_mapped_external_port (FsUpnpSimpleIgd *igd, gchar *proto,
-    gchar *external_ip, gchar *replaces_external_ip, guint external_port,
-    gchar *local_ip, guint local_port,
-    gchar *description, gpointer user_data)
-{
-  GSource *src;
-
-  g_debug ("proto:%s ex:%s oldex:%s exp:%u local:%s localp:%u desc:%s",
-      proto, external_ip, replaces_external_ip, external_port, local_ip,
-      local_port, description);
-
-  src = g_timeout_source_new_seconds (30);
-  g_source_set_callback (src, _remove_port, user_data, NULL);
-  g_source_attach (src, ctx);
-}
-
-
-
-static void
-_error_mapping_external_port (FsUpnpSimpleIgd *igd, GError *error,
-    gchar *proto, guint external_port,
-    gchar *description, gpointer user_data)
-{
-  g_error ("proto:%s port:%u desc:%s error: %s", proto, external_port,
-      description, error->message);
-}
-
-
-static void
-_error (FsUpnpSimpleIgd *igd, GError *error, gpointer user_data)
-{
-  g_error ("error: %s", error->message);
-}
-int
-main (int argc, char **argv)
-{
-
-  if (argc != 5)
-  {
-    g_print ("Usage: %s <external port> <local ip> <local port> <description>\n",
-        argv[0]);
-    return 0;
-  }
-
-  external_port = atoi (argv[1]);
-  internal_port = atoi (argv[3]);
-  g_return_val_if_fail (external_port && internal_port, 1);
-
-  g_type_init ();
-  g_thread_init (NULL);
-
-  ctx = g_main_context_new ();
-  loop = g_main_loop_new (ctx, FALSE);
-
-  igd = fs_upnp_simple_igd_new (ctx);
-
-  g_signal_connect (igd, "mapped-external-port",
-      G_CALLBACK (_mapped_external_port),
-      NULL);
-  g_signal_connect (igd, "error", G_CALLBACK (_error),
-      NULL);
-  g_signal_connect (igd, "error-mapping-port",
-      G_CALLBACK (_error_mapping_external_port),
-      NULL);
-
-  fs_upnp_simple_igd_add_port (igd, "TCP", external_port, argv[2],
-      internal_port, 20, argv[4]);
-
-  g_main_loop_run (loop);
-
-  g_object_unref (igd);
-  g_main_loop_unref (loop);
-  g_main_context_unref (ctx);
-
-  return 0;
-}
diff --git a/tests/commandline/test-thread.c b/tests/commandline/test-thread.c
new file mode 100644
index 0000000..546f46b
--- /dev/null
+++ b/tests/commandline/test-thread.c
@@ -0,0 +1,85 @@
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "fs-upnp-simple-igd-thread.h"
+
+static void
+_mapped_external_port (FsUpnpSimpleIgd *igd, gchar *proto,
+    gchar *external_ip, gchar *replaces_external_ip, guint external_port,
+    gchar *local_ip, guint local_port,
+    gchar *description, gpointer user_data)
+{
+  g_debug ("proto:%s ex:%s oldex:%s exp:%u local:%s localp:%u desc:%s",
+      proto, external_ip, replaces_external_ip, external_port, local_ip,
+      local_port, description);
+
+}
+
+
+
+static void
+_error_mapping_external_port (FsUpnpSimpleIgd *igd, GError *error,
+    gchar *proto, guint external_port,
+    gchar *description, gpointer user_data)
+{
+  g_error ("proto:%s port:%u desc:%s error: %s", proto, external_port,
+      description, error->message);
+}
+
+
+static void
+_error (FsUpnpSimpleIgd *igd, GError *error, gpointer user_data)
+{
+  g_error ("error: %s", error->message);
+}
+
+int
+main (int argc, char **argv)
+{
+  FsUpnpSimpleIgdThread *igd = NULL;
+  guint external_port, internal_port;
+
+
+  if (argc != 5)
+  {
+    g_print ("Usage: %s <external port> <local ip> <local port> <description>\n",
+        argv[0]);
+    return 0;
+  }
+
+  external_port = atoi (argv[1]);
+  internal_port = atoi (argv[3]);
+  g_return_val_if_fail (external_port && internal_port, 1);
+
+  g_type_init ();
+  g_thread_init (NULL);
+
+  igd = fs_upnp_simple_igd_thread_new ();
+
+  g_signal_connect (igd, "mapped-external-port",
+      G_CALLBACK (_mapped_external_port),
+      NULL);
+  g_signal_connect (igd, "error", G_CALLBACK (_error),
+      NULL);
+  g_signal_connect (igd, "error-mapping-port",
+      G_CALLBACK (_error_mapping_external_port),
+      NULL);
+
+  fs_upnp_simple_igd_add_port (FS_UPNP_SIMPLE_IGD (igd),
+      "TCP", external_port, argv[2],
+      internal_port, 20, argv[4]);
+
+  sleep (30);
+
+  fs_upnp_simple_igd_remove_port (FS_UPNP_SIMPLE_IGD (igd), "TCP",
+      external_port);
+
+  sleep (5);
+
+  g_object_unref (igd);
+
+  return 0;
+}
diff --git a/tests/commandline/test.c b/tests/commandline/test.c
new file mode 100644
index 0000000..19d58c0
--- /dev/null
+++ b/tests/commandline/test.c
@@ -0,0 +1,98 @@
+
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include "fs-upnp-simple-igd.h"
+
+GMainContext *ctx = NULL;
+GMainLoop *loop = NULL;
+FsUpnpSimpleIgd *igd = NULL;
+guint external_port, internal_port;
+
+static gboolean
+_remove_port (gpointer user_data)
+{
+  g_debug ("removing port");
+  fs_upnp_simple_igd_remove_port (igd, "TCP", external_port);
+
+  return FALSE;
+}
+
+static void
+_mapped_external_port (FsUpnpSimpleIgd *igd, gchar *proto,
+    gchar *external_ip, gchar *replaces_external_ip, guint external_port,
+    gchar *local_ip, guint local_port,
+    gchar *description, gpointer user_data)
+{
+  GSource *src;
+
+  g_debug ("proto:%s ex:%s oldex:%s exp:%u local:%s localp:%u desc:%s",
+      proto, external_ip, replaces_external_ip, external_port, local_ip,
+      local_port, description);
+
+  src = g_timeout_source_new_seconds (30);
+  g_source_set_callback (src, _remove_port, user_data, NULL);
+  g_source_attach (src, ctx);
+}
+
+
+
+static void
+_error_mapping_external_port (FsUpnpSimpleIgd *igd, GError *error,
+    gchar *proto, guint external_port,
+    gchar *description, gpointer user_data)
+{
+  g_error ("proto:%s port:%u desc:%s error: %s", proto, external_port,
+      description, error->message);
+}
+
+
+static void
+_error (FsUpnpSimpleIgd *igd, GError *error, gpointer user_data)
+{
+  g_error ("error: %s", error->message);
+}
+int
+main (int argc, char **argv)
+{
+
+  if (argc != 5)
+  {
+    g_print ("Usage: %s <external port> <local ip> <local port> <description>\n",
+        argv[0]);
+    return 0;
+  }
+
+  external_port = atoi (argv[1]);
+  internal_port = atoi (argv[3]);
+  g_return_val_if_fail (external_port && internal_port, 1);
+
+  g_type_init ();
+  g_thread_init (NULL);
+
+  ctx = g_main_context_new ();
+  loop = g_main_loop_new (ctx, FALSE);
+
+  igd = fs_upnp_simple_igd_new (ctx);
+
+  g_signal_connect (igd, "mapped-external-port",
+      G_CALLBACK (_mapped_external_port),
+      NULL);
+  g_signal_connect (igd, "error", G_CALLBACK (_error),
+      NULL);
+  g_signal_connect (igd, "error-mapping-port",
+      G_CALLBACK (_error_mapping_external_port),
+      NULL);
+
+  fs_upnp_simple_igd_add_port (igd, "TCP", external_port, argv[2],
+      internal_port, 20, argv[4]);
+
+  g_main_loop_run (loop);
+
+  g_object_unref (igd);
+  g_main_loop_unref (loop);
+  g_main_context_unref (ctx);
+
+  return 0;
+}
-- 
1.5.6.5




More information about the farsight-commits mailing list