Mercurial > pidgin
changeset 27108:38c4973b5222
Add a function to remove a port mapping (UPnP or NAT-PMP) given a file
descriptor.
Adapt the XMPP PRPL to use this to remove port mappings when a file transfer
is done.
There is still no support for removing left-over mappings at exit, since I've
found no good way of calling purple_upnp_remove_port_mapping (which relies on
callbacks) from purple_network_uninit (since the main thread terminates after
the _uninit functions have finished)...
author | Marcus Lundblad <ml@update.uu.se> |
---|---|
date | Mon, 15 Jun 2009 21:43:25 +0000 |
parents | 55811a205c71 |
children | bd84462b0e17 455e679ea0db |
files | ChangeLog.API libpurple/network.c libpurple/network.h libpurple/protocols/jabber/si.c |
diffstat | 4 files changed, 93 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog.API Fri Jun 12 21:00:44 2009 +0000 +++ b/ChangeLog.API Mon Jun 15 21:43:25 2009 +0000 @@ -39,6 +39,7 @@ * purple_network_set_turn_server * purple_network_get_stun_ip * purple_network_get_turn_ip + * purple_network_remove_port_mapping * purple_proxy_connect_udp * purple_prpl_get_media_caps * purple_prpl_got_account_actions
--- a/libpurple/network.c Fri Jun 12 21:00:44 2009 +0000 +++ b/libpurple/network.c Mon Jun 15 21:43:25 2009 +0000 @@ -105,6 +105,10 @@ static gchar *stun_ip = NULL; static gchar *turn_ip = NULL; +/* Keep track of port mappings done with UPnP and NAT-PMP */ +static GHashTable *upnp_port_mappings = NULL; +static GHashTable *nat_pmp_port_mappings = NULL; + const unsigned char * purple_network_ip_atoi(const char *ip) { @@ -257,6 +261,15 @@ return; } + if (success) { + /* add port mapping to hash table */ + gint *key = g_new(gint, 1); + gint *value = g_new(gint, 1); + *key = purple_network_get_port_from_fd(listen_data->listenfd); + *value = listen_data->socket_type; + g_hash_table_insert(upnp_port_mappings, key, value); + } + if (listen_data->cb) listen_data->cb(listen_data->listenfd, listen_data->cb_data); @@ -892,6 +905,59 @@ return &handle; } +static void +purple_network_upnp_mapping_remove_cb(gboolean sucess, gpointer data) +{ + purple_debug_info("network", "done removing UPnP port mapping\n"); +} + +/* the reason for these functions to have these signatures is to be able to + use them for g_hash_table_foreach to clean remaining port mappings, which is + not yet done */ +static void +purple_network_upnp_mapping_remove(gpointer key, gpointer value, + gpointer user_data) +{ + gint port = (gint) *((gint *) key); + gint protocol = (gint) *((gint *) value); + purple_debug_info("network", "removing UPnP port mapping for port %d\n", + port); + purple_upnp_remove_port_mapping(port, + protocol == SOCK_STREAM ? "TCP" : "UDP", + purple_network_upnp_mapping_remove_cb, NULL); +} + +static void +purple_network_nat_pmp_mapping_remove(gpointer key, gpointer value, + gpointer user_data) +{ + gint port = (gint) *((gint *) key); + gint protocol = (gint) *((gint *) value); + purple_debug_info("network", "removing NAT-PMP port mapping for port %d\n", + port); + purple_pmp_destroy_map( + protocol == SOCK_STREAM ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP, + port); +} + +void +purple_network_remove_port_mapping(gint fd) +{ + int port = purple_network_get_port_from_fd(fd); + gint *protocol = g_hash_table_lookup(upnp_port_mappings, &port); + + if (protocol) { + purple_network_upnp_mapping_remove(&port, protocol, NULL); + g_hash_table_remove(upnp_port_mappings, protocol); + } else { + protocol = g_hash_table_lookup(nat_pmp_port_mappings, &port); + if (protocol) { + purple_network_nat_pmp_mapping_remove(&port, protocol, NULL); + g_hash_table_remove(nat_pmp_port_mappings, protocol); + } + } +} + void purple_network_init(void) { @@ -964,8 +1030,15 @@ purple_prefs_get_string("/purple/network/stun_server")); purple_network_set_turn_server( purple_prefs_get_string("/purple/network/turn_server")); + + upnp_port_mappings = + g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free); + nat_pmp_port_mappings = + g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free); } + + void purple_network_uninit(void) { @@ -1008,4 +1081,10 @@ if (stun_ip) g_free(stun_ip); + + g_hash_table_destroy(upnp_port_mappings); + g_hash_table_destroy(nat_pmp_port_mappings); + + /* TODO: clean up remaining port mappings, note calling + purple_upnp_remove_port_mapping from here doesn't quite work... */ }
--- a/libpurple/network.h Fri Jun 12 21:00:44 2009 +0000 +++ b/libpurple/network.h Mon Jun 15 21:43:25 2009 +0000 @@ -259,7 +259,14 @@ */ const gchar *purple_network_get_turn_ip(void); - +/** + * Remove a port mapping (UPnP or NAT-PMP) associated with listening socket + * + * @param fd Socket to remove the port mapping for + * @since 2.6.0 + */ +void purple_network_remove_port_mapping(gint fd); + /** * Initializes the network subsystem. */
--- a/libpurple/protocols/jabber/si.c Fri Jun 12 21:00:44 2009 +0000 +++ b/libpurple/protocols/jabber/si.c Mon Jun 15 21:43:25 2009 +0000 @@ -1321,6 +1321,11 @@ jabber_iq_remove_callback_by_id(js, jsx->iq_id); if (jsx->local_streamhost_fd >= 0) close(jsx->local_streamhost_fd); + if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && + xfer->fd >= 0) { + purple_debug_info("jabber", "remove port mapping\n"); + purple_network_remove_port_mapping(xfer->fd); + } if (jsx->connect_timeout > 0) purple_timeout_remove(jsx->connect_timeout); if (jsx->ibb_timeout_handle > 0)