2
* GUPnP Simple IGD abstraction
4
* Copyright 2008 Collabora Ltd.
5
* @author: Olivier Crete <olivier.crete@collabora.co.uk>
6
* Copyright 2008 Nokia Corp.
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License as published by the Free Software Foundation; either
11
* version 2.1 of the License, or (at your option) any later version.
13
* This library is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25
* SECTION:gupnp-simple-igd
26
* @short_description: A simple class to map ports on UPnP routers
28
* This simple class allows applications to map ports on UPnP routers.
29
* It implements the basic functionalities to map ports to external ports.
30
* It also allows implementations to know the external port from the router's
35
#include "gupnp-simple-igd.h"
36
#include "gupnp-simple-igd-marshal.h"
40
#include <libgupnp/gupnp-control-point.h>
43
struct _GUPnPSimpleIgdPrivate
45
GMainContext *main_context;
47
GUPnPContext *gupnp_context;
48
GUPnPControlPoint *ip_cp;
49
GUPnPControlPoint *ppp_cp;
51
GPtrArray *service_proxies;
55
gulong ip_avail_handler;
56
gulong ip_unavail_handler;
58
gulong ppp_avail_handler;
59
gulong ppp_unavail_handler;
63
GUPnPSimpleIgd *parent;
64
GUPnPServiceProxy *proxy;
67
GUPnPServiceProxyAction *external_ip_action;
68
gboolean external_ip_failed;
70
GPtrArray *proxymappings;
78
guint32 lease_duration;
84
struct Mapping *mapping;
86
GUPnPServiceProxyAction *action;
96
SIGNAL_MAPPED_EXTERNAL_PORT,
97
SIGNAL_ERROR_MAPPING_PORT,
105
PROP_REQUEST_TIMEOUT,
110
static guint signals[LAST_SIGNAL] = { 0 };
113
#define GUPNP_SIMPLE_IGD_GET_PRIVATE(o) \
114
(G_TYPE_INSTANCE_GET_PRIVATE ((o), GUPNP_TYPE_SIMPLE_IGD, \
115
GUPnPSimpleIgdPrivate))
118
G_DEFINE_TYPE (GUPnPSimpleIgd, gupnp_simple_igd, G_TYPE_OBJECT);
121
static void gupnp_simple_igd_constructed (GObject *object);
122
static void gupnp_simple_igd_dispose (GObject *object);
123
static void gupnp_simple_igd_finalize (GObject *object);
124
static void gupnp_simple_igd_get_property (GObject *object, guint prop_id,
125
GValue *value, GParamSpec *pspec);
126
static void gupnp_simple_igd_set_property (GObject *object, guint prop_id,
127
const GValue *value, GParamSpec *pspec);
129
static void gupnp_simple_igd_gather (GUPnPSimpleIgd *self,
131
static void gupnp_simple_igd_add_proxy_mapping (GUPnPSimpleIgd *self,
133
struct Mapping *mapping);
135
static void free_proxy (struct Proxy *prox);
136
static void free_mapping (struct Mapping *mapping);
138
static void stop_proxymapping (struct ProxyMapping *pm);
140
static void gupnp_simple_igd_add_port_real (GUPnPSimpleIgd *self,
141
const gchar *protocol,
142
guint16 external_port,
143
const gchar *local_ip,
145
guint32 lease_duration,
146
const gchar *description);
147
static void gupnp_simple_igd_remove_port_real (GUPnPSimpleIgd *self,
148
const gchar *protocol,
149
guint external_port);
152
gupnp_simple_igd_get_error_domain (void)
154
return g_quark_from_static_string ("fs-upnp-simple-igd-error");
159
gupnp_simple_igd_class_init (GUPnPSimpleIgdClass *klass)
161
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
163
g_type_class_add_private (klass, sizeof (GUPnPSimpleIgdPrivate));
165
gobject_class->constructed = gupnp_simple_igd_constructed;
166
gobject_class->dispose = gupnp_simple_igd_dispose;
167
gobject_class->finalize = gupnp_simple_igd_finalize;
168
gobject_class->set_property = gupnp_simple_igd_set_property;
169
gobject_class->get_property = gupnp_simple_igd_get_property;
171
klass->add_port = gupnp_simple_igd_add_port_real;
172
klass->remove_port = gupnp_simple_igd_remove_port_real;
174
g_object_class_install_property (gobject_class,
175
PROP_REQUEST_TIMEOUT,
176
g_param_spec_uint ("request-timeout",
177
"The timeout after which a request is considered to have failed",
178
"After this timeout, the request is considered to have failed and"
179
"is dropped (in seconds).",
183
g_object_class_install_property (gobject_class,
185
g_param_spec_pointer ("main-context",
186
"The GMainContext to use",
187
"This GMainContext will be used for all async activities",
188
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
191
* GUPnPSimpleIgd::mapped-external-port
192
* @self: #GUPnPSimpleIgd that emitted the signal
193
* @proto: the requested protocol ("UDP" or "TCP")
194
* @external_ip: the external IP
195
* @replaces_external_ip: if this mapping replaces another mapping,
196
* this is the old external IP
197
* @external_port: the external port
198
* @local_ip: internal ip this is forwarded to
199
* @local_port: the local port
200
* @description: the user's selected description
202
* This signal means that an IGD has been found that that adding a port
203
* mapping has succeeded.
206
signals[SIGNAL_MAPPED_EXTERNAL_PORT] = g_signal_new ("mapped-external-port",
207
G_TYPE_FROM_CLASS (klass),
212
_gupnp_simple_igd_marshal_VOID__STRING_STRING_STRING_UINT_STRING_UINT_STRING,
213
G_TYPE_NONE, 7, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT,
214
G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING);
217
* GUPnPSimpleIgd::error-mapping-port
218
* @self: #GUPnPSimpleIgd that emitted the signal
220
* @proto: The requested protocol
221
* @external_port: the requested external port
222
* @description: the passed description
224
* This means that mapping a port on a specific IGD has failed (it may still
225
* succeed on other IGDs on the network).
227
signals[SIGNAL_ERROR_MAPPING_PORT] = g_signal_new ("error-mapping-port",
228
G_TYPE_FROM_CLASS (klass),
229
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
233
_gupnp_simple_igd_marshal_VOID__POINTER_STRING_UINT_STRING,
234
G_TYPE_NONE, 4, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_UINT,
239
gupnp_simple_igd_init (GUPnPSimpleIgd *self)
241
self->priv = GUPNP_SIMPLE_IGD_GET_PRIVATE (self);
243
self->priv->service_proxies = g_ptr_array_new ();
244
self->priv->mappings = g_ptr_array_new ();
248
gupnp_simple_igd_dispose (GObject *object)
250
GUPnPSimpleIgd *self = GUPNP_SIMPLE_IGD_CAST (object);
252
if (self->priv->ip_avail_handler)
253
g_signal_handler_disconnect (self->priv->ip_cp,
254
self->priv->ip_avail_handler);
255
self->priv->ip_avail_handler = 0;
257
if (self->priv->ip_unavail_handler)
258
g_signal_handler_disconnect (self->priv->ip_cp,
259
self->priv->ip_unavail_handler);
260
self->priv->ip_unavail_handler = 0;
262
if (self->priv->ppp_avail_handler)
263
g_signal_handler_disconnect (self->priv->ppp_cp,
264
self->priv->ppp_avail_handler);
265
self->priv->ppp_avail_handler = 0;
267
if (self->priv->ppp_unavail_handler)
268
g_signal_handler_disconnect (self->priv->ppp_cp,
269
self->priv->ppp_unavail_handler);
270
self->priv->ppp_unavail_handler = 0;
272
while (self->priv->mappings->len)
275
g_ptr_array_index (self->priv->mappings, 0));
276
g_ptr_array_remove_index_fast (self->priv->mappings, 0);
279
while (self->priv->service_proxies->len)
282
g_ptr_array_index (self->priv->service_proxies, 0));
283
g_ptr_array_remove_index_fast (self->priv->service_proxies, 0);
286
if (self->priv->ip_cp)
287
g_object_unref (self->priv->ip_cp);
288
self->priv->ip_cp = NULL;
290
if (self->priv->ppp_cp)
291
g_object_unref (self->priv->ppp_cp);
292
self->priv->ppp_cp = NULL;
294
if (self->priv->gupnp_context)
295
g_object_unref (self->priv->gupnp_context);
296
self->priv->gupnp_context = NULL;
298
G_OBJECT_CLASS (gupnp_simple_igd_parent_class)->dispose (object);
303
_external_ip_address_changed (GUPnPServiceProxy *proxy, const gchar *variable,
304
GValue *value, gpointer user_data)
306
struct Proxy *prox = user_data;
310
g_return_if_fail (G_VALUE_HOLDS_STRING(value));
312
new_ip = g_value_dup_string (value);
314
for (i=0; i < prox->proxymappings->len; i++)
316
struct ProxyMapping *pm = g_ptr_array_index (prox->proxymappings, i);
319
g_signal_emit (prox->parent, signals[SIGNAL_MAPPED_EXTERNAL_PORT], 0,
320
pm->mapping->protocol, new_ip, prox->external_ip,
321
pm->mapping->external_port, pm->mapping->local_ip,
322
pm->mapping->local_port, pm->mapping->description);
325
g_free (prox->external_ip);
326
prox->external_ip = new_ip;
330
free_proxymapping (struct ProxyMapping *pm)
332
g_slice_free (struct ProxyMapping, pm);
336
free_proxy (struct Proxy *prox)
338
if (prox->external_ip_action)
339
gupnp_service_proxy_cancel_action (prox->proxy, prox->external_ip_action);
341
gupnp_service_proxy_remove_notify (prox->proxy, "ExternalIPAddress",
342
_external_ip_address_changed, prox);
344
g_object_unref (prox->proxy);
345
g_ptr_array_foreach (prox->proxymappings, (GFunc) stop_proxymapping, NULL);
346
g_ptr_array_foreach (prox->proxymappings, (GFunc) free_proxymapping, NULL);
347
g_ptr_array_free (prox->proxymappings, TRUE);
348
g_free (prox->external_ip);
349
g_slice_free (struct Proxy, prox);
353
free_mapping (struct Mapping *mapping)
355
g_free (mapping->protocol);
356
g_free (mapping->local_ip);
357
g_free (mapping->description);
358
g_slice_free (struct Mapping, mapping);
362
gupnp_simple_igd_finalize (GObject *object)
364
GUPnPSimpleIgd *self = GUPNP_SIMPLE_IGD_CAST (object);
366
g_main_context_unref (self->priv->main_context);
368
g_warn_if_fail (self->priv->service_proxies->len == 0);
369
g_ptr_array_free (self->priv->service_proxies, TRUE);
371
g_warn_if_fail (self->priv->mappings->len == 0);
372
g_ptr_array_free (self->priv->mappings, TRUE);
374
G_OBJECT_CLASS (gupnp_simple_igd_parent_class)->finalize (object);
378
gupnp_simple_igd_get_property (GObject *object, guint prop_id,
379
GValue *value, GParamSpec *pspec)
381
GUPnPSimpleIgd *self = GUPNP_SIMPLE_IGD_CAST (object);
384
case PROP_REQUEST_TIMEOUT:
386
SoupSession *session;
387
session = gupnp_context_get_session (self->priv->gupnp_context);
388
g_object_get_property (G_OBJECT (session), "timeout", value);
391
case PROP_MAIN_CONTEXT:
392
g_value_set_pointer (value, self->priv->main_context);
395
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
402
gupnp_simple_igd_set_property (GObject *object, guint prop_id,
403
const GValue *value, GParamSpec *pspec)
405
GUPnPSimpleIgd *self = GUPNP_SIMPLE_IGD_CAST (object);
408
case PROP_REQUEST_TIMEOUT:
410
SoupSession *session;
411
session = gupnp_context_get_session (self->priv->gupnp_context);
412
g_object_set_property (G_OBJECT (session), "timeout", value);
415
case PROP_MAIN_CONTEXT:
416
if (!self->priv->main_context && g_value_get_pointer (value))
418
self->priv->main_context = g_value_get_pointer (value);
419
g_main_context_ref (self->priv->main_context);
423
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
429
_cp_service_avail (GUPnPControlPoint *cp,
430
GUPnPServiceProxy *proxy,
431
GUPnPSimpleIgd *self)
433
struct Proxy *prox = g_slice_new0 (struct Proxy);
437
prox->proxy = g_object_ref (proxy);
438
prox->proxymappings = g_ptr_array_new ();
440
gupnp_simple_igd_gather (self, prox);
442
for (i = 0; i < self->priv->mappings->len; i++)
443
gupnp_simple_igd_add_proxy_mapping (self, prox,
444
g_ptr_array_index (self->priv->mappings, i));
446
g_ptr_array_add(self->priv->service_proxies, prox);
451
_cp_service_unavail (GUPnPControlPoint *cp,
452
GUPnPServiceProxy *proxy,
453
GUPnPSimpleIgd *self)
457
for (i=0; i < self->priv->service_proxies->len; i++)
460
g_ptr_array_index (self->priv->service_proxies, i);
462
if (!strcmp (gupnp_service_info_get_udn (GUPNP_SERVICE_INFO (prox->proxy)),
463
gupnp_service_info_get_udn (GUPNP_SERVICE_INFO (prox->proxy))))
465
g_ptr_array_foreach (prox->proxymappings, (GFunc) stop_proxymapping,
467
g_ptr_array_foreach (prox->proxymappings, (GFunc) free_proxymapping,
470
g_ptr_array_remove_index_fast (self->priv->service_proxies, i);
478
gupnp_simple_igd_constructed (GObject *object)
480
GUPnPSimpleIgd *self = GUPNP_SIMPLE_IGD_CAST (object);
481
SoupSession *session;
483
if (!self->priv->main_context)
484
self->priv->main_context = g_main_context_ref (g_main_context_default ());
486
self->priv->gupnp_context = gupnp_context_new (self->priv->main_context,
488
g_return_if_fail (self->priv->gupnp_context);
490
session = gupnp_context_get_session (self->priv->gupnp_context);
491
g_object_set (session, "timeout", 5, NULL);
493
self->priv->ip_cp = gupnp_control_point_new (self->priv->gupnp_context,
494
"urn:schemas-upnp-org:service:WANIPConnection:1");
495
g_return_if_fail (self->priv->ip_cp);
497
self->priv->ip_avail_handler = g_signal_connect (self->priv->ip_cp,
498
"service-proxy-available",
499
G_CALLBACK (_cp_service_avail), self);
500
self->priv->ip_unavail_handler = g_signal_connect (self->priv->ip_cp,
501
"service-proxy-unavailable",
502
G_CALLBACK (_cp_service_unavail), self);
504
self->priv->ppp_cp = gupnp_control_point_new (self->priv->gupnp_context,
505
"urn:schemas-upnp-org:service:WANPPPConnection:1");
506
g_return_if_fail (self->priv->ppp_cp);
508
self->priv->ppp_avail_handler = g_signal_connect (self->priv->ppp_cp,
509
"service-proxy-available",
510
G_CALLBACK (_cp_service_avail), self);
511
self->priv->ppp_unavail_handler = g_signal_connect (self->priv->ppp_cp,
512
"service-proxy-unavailable",
513
G_CALLBACK (_cp_service_unavail), self);
516
gssdp_resource_browser_set_active (
517
GSSDP_RESOURCE_BROWSER (self->priv->ip_cp),
519
gssdp_resource_browser_set_active (
520
GSSDP_RESOURCE_BROWSER (self->priv->ppp_cp),
523
if (G_OBJECT_CLASS (gupnp_simple_igd_parent_class)->constructed)
524
G_OBJECT_CLASS (gupnp_simple_igd_parent_class)->constructed (object);
528
* gupnp_simple_igd_new:
529
* @main_context: the #GMainContext to use (may be NULL for the default
532
* This creates a new #GUPnpSimpleIgd object using the special GMainContext
534
* Returns: a new #GUPnPSimpleIgd
538
gupnp_simple_igd_new (GMainContext *main_context)
540
return g_object_new (GUPNP_TYPE_SIMPLE_IGD,
541
"main-context", main_context, NULL);
546
_service_proxy_got_external_ip_address (GUPnPServiceProxy *proxy,
547
GUPnPServiceProxyAction *action,
550
struct Proxy *prox = user_data;
551
GUPnPSimpleIgd *self = prox->parent;
552
GError *error = NULL;
555
g_return_if_fail (prox->external_ip_action == action);
557
prox->external_ip_action = NULL;
559
if (gupnp_service_proxy_end_action (proxy, action, &error,
560
"NewExternalIPAddress", G_TYPE_STRING, &ip,
565
for (i=0; i < prox->proxymappings->len; i++)
567
struct ProxyMapping *pm = g_ptr_array_index (prox->proxymappings, i);
570
g_signal_emit (self, signals[SIGNAL_MAPPED_EXTERNAL_PORT], 0,
571
pm->mapping->protocol, ip, prox->external_ip,
572
pm->mapping->external_port, pm->mapping->local_ip,
573
pm->mapping->local_port, pm->mapping->description);
576
g_free (prox->external_ip);
577
prox->external_ip = ip;
583
prox->external_ip_failed = TRUE;
584
g_return_if_fail (error);
586
for (i=0; i < prox->proxymappings->len; i++)
588
struct ProxyMapping *pm = g_ptr_array_index (prox->proxymappings, i);
590
g_signal_emit (self, signals[SIGNAL_ERROR_MAPPING_PORT], error->domain,
591
error, pm->mapping->protocol, pm->mapping->external_port,
592
pm->mapping->description);
595
g_clear_error (&error);
599
gupnp_simple_igd_gather (GUPnPSimpleIgd *self,
602
prox->external_ip_action = gupnp_service_proxy_begin_action (prox->proxy,
603
"GetExternalIPAddress",
604
_service_proxy_got_external_ip_address, prox, NULL);
606
gupnp_service_proxy_add_notify (prox->proxy, "ExternalIPAddress",
607
G_TYPE_STRING, _external_ip_address_changed, prox);
609
gupnp_service_proxy_set_subscribed (prox->proxy, TRUE);
613
_service_proxy_renewed_port_mapping (GUPnPServiceProxy *proxy,
614
GUPnPServiceProxyAction *action,
617
struct ProxyMapping *pm = user_data;
618
GUPnPSimpleIgd *self = pm->proxy->parent;
619
GError *error = NULL;
621
if (!gupnp_service_proxy_end_action (proxy, action, &error,
624
g_return_if_fail (error);
625
g_signal_emit (self, signals[SIGNAL_ERROR_MAPPING_PORT], error->domain,
626
error, pm->mapping->protocol, pm->mapping->external_port,
627
pm->mapping->description);
629
g_clear_error (&error);
633
_renew_mapping_timeout (gpointer user_data)
635
struct ProxyMapping *pm = user_data;
637
gupnp_service_proxy_begin_action (pm->proxy->proxy,
639
_service_proxy_renewed_port_mapping, pm,
640
"NewRemoteHost", G_TYPE_STRING, "",
641
"NewExternalPort", G_TYPE_UINT, pm->mapping->external_port,
642
"NewProtocol", G_TYPE_STRING, pm->mapping->protocol,
643
"NewInternalPort", G_TYPE_UINT, pm->mapping->local_port,
644
"NewInternalClient", G_TYPE_STRING, pm->mapping->local_ip,
645
"NewEnabled", G_TYPE_BOOLEAN, TRUE,
646
"NewPortMappingDescription", G_TYPE_STRING, pm->mapping->description,
647
"NewLeaseDuration", G_TYPE_UINT, pm->mapping->lease_duration,
654
_service_proxy_added_port_mapping (GUPnPServiceProxy *proxy,
655
GUPnPServiceProxyAction *action,
658
struct ProxyMapping *pm = user_data;
659
GUPnPSimpleIgd *self = pm->proxy->parent;
660
GError *error = NULL;
662
g_return_if_fail (pm->action == action);
666
if (gupnp_service_proxy_end_action (proxy, action, &error,
671
if (pm->proxy->external_ip)
672
g_signal_emit (self, signals[SIGNAL_MAPPED_EXTERNAL_PORT], 0,
673
pm->mapping->protocol, pm->proxy->external_ip, NULL,
674
pm->mapping->external_port, pm->mapping->local_ip,
675
pm->mapping->local_port, pm->mapping->description);
680
g_timeout_source_new_seconds (pm->mapping->lease_duration / 2);
681
g_source_set_callback (pm->renew_src,
682
_renew_mapping_timeout, pm, NULL);
683
g_source_attach (pm->renew_src, self->priv->main_context);
688
g_return_if_fail (error);
689
g_signal_emit (self, signals[SIGNAL_ERROR_MAPPING_PORT], error->domain,
690
error, pm->mapping->protocol, pm->mapping->external_port,
691
pm->mapping->description);
693
g_clear_error (&error);
695
stop_proxymapping (pm);
699
gupnp_simple_igd_add_proxy_mapping (GUPnPSimpleIgd *self, struct Proxy *prox,
700
struct Mapping *mapping)
702
struct ProxyMapping *pm = g_slice_new0 (struct ProxyMapping);
705
pm->mapping = mapping;
707
pm->action = gupnp_service_proxy_begin_action (prox->proxy,
709
_service_proxy_added_port_mapping, pm,
710
"NewRemoteHost", G_TYPE_STRING, "",
711
"NewExternalPort", G_TYPE_UINT, mapping->external_port,
712
"NewProtocol", G_TYPE_STRING, mapping->protocol,
713
"NewInternalPort", G_TYPE_UINT, mapping->local_port,
714
"NewInternalClient", G_TYPE_STRING, mapping->local_ip,
715
"NewEnabled", G_TYPE_BOOLEAN, TRUE,
716
"NewPortMappingDescription", G_TYPE_STRING, mapping->description,
717
"NewLeaseDuration", G_TYPE_UINT, mapping->lease_duration,
720
g_ptr_array_add (prox->proxymappings, pm);
724
gupnp_simple_igd_add_port_real (GUPnPSimpleIgd *self,
725
const gchar *protocol,
726
guint16 external_port,
727
const gchar *local_ip,
729
guint32 lease_duration,
730
const gchar *description)
732
struct Mapping *mapping = g_slice_new0 (struct Mapping);
735
g_return_if_fail (protocol && local_ip);
736
g_return_if_fail (!strcmp (protocol, "UDP") || !strcmp (protocol, "TCP"));
738
mapping->protocol = g_strdup (protocol);
739
mapping->external_port = external_port;
740
mapping->local_ip = g_strdup (local_ip);
741
mapping->local_port = local_port;
742
mapping->lease_duration = lease_duration;
743
mapping->description = g_strdup (description);
745
if (!mapping->description)
746
mapping->description = g_strdup ("");
748
g_ptr_array_add (self->priv->mappings, mapping);
750
for (i=0; i < self->priv->service_proxies->len; i++)
752
struct Proxy *prox = g_ptr_array_index (self->priv->service_proxies, i);
754
if (prox->external_ip_failed)
756
GError error = {GUPNP_SIMPLE_IGD_ERROR,
757
GUPNP_SIMPLE_IGD_ERROR_EXTERNAL_ADDRESS,
758
"Could not get external address"};
759
g_signal_emit (self, signals[SIGNAL_ERROR_MAPPING_PORT],
760
GUPNP_SIMPLE_IGD_ERROR,
761
&error, mapping->protocol, mapping->external_port,
762
mapping->description);
766
gupnp_simple_igd_add_proxy_mapping (self, prox, mapping);
772
* gupnp_simple_igd_add_port:
773
* @self: The #GUPnPSimpleIgd object
774
* @protocol: the protocol "UDP" or "TCP"
775
* @external_port: The port to try to open on the external device
776
* @local_ip: The IP address to forward packets to (most likely the local ip address)
777
* @local_port: The local port to forward packets to
778
* @lease_duration: The duration of the lease (it will be auto-renewed before it expires). This is in seconds.
779
* @description: The description that will appear in the router's table
781
* This adds a port to the router's forwarding table. The mapping will
782
* be automatically refreshed by this object until it is either removed with
783
* gupnp_simple_igd_remove_port() or the object disapears.
785
* If there is a problem, the #GUPnPSimpleIgd::error-mapping-port signal will
786
* be emitted. If a router is found and a port is mapped correctly,
787
* #GUPnPSimpleIgd::mapped-external-port will be emitted. These signals may
788
* be emitted multiple times if there are multiple routers present.
792
gupnp_simple_igd_add_port (GUPnPSimpleIgd *self,
793
const gchar *protocol,
794
guint16 external_port,
795
const gchar *local_ip,
797
guint32 lease_duration,
798
const gchar *description)
800
GUPnPSimpleIgdClass *klass = GUPNP_SIMPLE_IGD_GET_CLASS (self);
802
g_return_if_fail (klass->add_port);
804
klass->add_port (self, protocol, external_port, local_ip, local_port,
805
lease_duration, description);
810
_service_proxy_delete_port_mapping (GUPnPServiceProxy *proxy,
811
GUPnPServiceProxyAction *action,
814
GError *error = NULL;
817
if (!gupnp_service_proxy_end_action (proxy, action, &error,
820
g_return_if_fail (error);
821
g_warning ("Error deleting port mapping: %s", error->message);
823
g_clear_error (&error);
827
gupnp_simple_igd_remove_port_real (GUPnPSimpleIgd *self,
828
const gchar *protocol,
832
struct Mapping *mapping = NULL;
834
g_return_if_fail (protocol);
836
for (i = 0; i < self->priv->mappings->len; i++)
838
struct Mapping *tmpmapping = g_ptr_array_index (self->priv->mappings, i);
839
if (tmpmapping->external_port == external_port &&
840
!strcmp (tmpmapping->protocol, protocol))
842
mapping = tmpmapping;
849
g_ptr_array_remove_index_fast (self->priv->mappings, i);
851
for (i=0; i < self->priv->service_proxies->len; i++)
853
struct Proxy *prox = g_ptr_array_index (self->priv->service_proxies, i);
855
for (j=0; j < prox->proxymappings->len; j++)
857
struct ProxyMapping *pm = g_ptr_array_index (prox->proxymappings, j);
858
if (pm->mapping == mapping)
860
stop_proxymapping (pm);
864
g_source_destroy (pm->renew_src);
865
g_source_unref (pm->renew_src);
867
pm->renew_src = NULL;
870
gupnp_service_proxy_begin_action (prox->proxy,
872
_service_proxy_delete_port_mapping, self,
873
"NewRemoteHost", G_TYPE_STRING, "",
874
"NewExternalPort", G_TYPE_UINT, mapping->external_port,
875
"NewProtocol", G_TYPE_STRING, mapping->protocol,
878
free_proxymapping (pm);
879
g_ptr_array_remove_index_fast (prox->proxymappings, j);
885
free_mapping (mapping);
889
* gupnp_simple_igd_remove_port:
890
* @self: The #GUPnPSimpleIgd object
891
* @protocol: the protocol "UDP" or "TCP" as given to
892
* gupnp_simple_igd_add_port()
893
* @external_port: The port to try to open on the external device as given to
894
* gupnp_simple_igd_add_port()
896
* This tries to remove a port entry from the routers that was previously added
897
* with gupnp_simple_igd_add_port(). There is no indicated of success or failure
898
* it is a best effort mechanism. If it fails, the bindings will disapears after
899
* the lease duration set when the port where added.
902
gupnp_simple_igd_remove_port (GUPnPSimpleIgd *self,
903
const gchar *protocol,
906
GUPnPSimpleIgdClass *klass = GUPNP_SIMPLE_IGD_GET_CLASS (self);
908
g_return_if_fail (klass->remove_port);
910
klass->remove_port (self, protocol, external_port);
914
stop_proxymapping (struct ProxyMapping *pm)
917
gupnp_service_proxy_cancel_action (pm->proxy->proxy,