diff libpurple/network.c @ 15441:56a2a0bb290a

Fix a crash when a network_listen_range process is canceled before its UPnP port mapping completes, which occurs regularly on certain routers when file transfers are initiated and then quickly finished. Much thanks to Elliott Harris and Eric Richie for their hard work with me hunting this down and fixing it.
author Evan Schoenberg <evan.s@dreskin.net>
date Sun, 28 Jan 2007 15:05:23 +0000
parents 5fe8042783c1
children 552be3958d6a
line wrap: on
line diff
--- a/libpurple/network.c	Sun Jan 28 01:24:15 2007 +0000
+++ b/libpurple/network.c	Sun Jan 28 15:05:23 2007 +0000
@@ -74,6 +74,7 @@
 	gboolean adding;
 	GaimNetworkListenCallback cb;
 	gpointer cb_data;
+	UPnPMappingAddRemove *mapping_data;
 };
 
 #ifdef HAVE_LIBNM
@@ -210,28 +211,29 @@
 		if (listen_data->retry) {
 			listen_data->retry = FALSE;
 			listen_data->adding = FALSE;
-			/* TODO: Need to keep track of this return value! */
-			gaim_upnp_remove_port_mapping(
-				gaim_network_get_port_from_fd(listen_data->listenfd),
-				(listen_data->socket_type == SOCK_STREAM) ? "TCP" : "UDP",
-				gaim_network_set_upnp_port_mapping_cb, listen_data);
+			listen_data->mapping_data = gaim_upnp_remove_port_mapping(
+						gaim_network_get_port_from_fd(listen_data->listenfd),
+						(listen_data->socket_type == SOCK_STREAM) ? "TCP" : "UDP",
+						gaim_network_set_upnp_port_mapping_cb, listen_data);
 			return;
 		}
 	} else if (!listen_data->adding) {
 		/* We've tried successfully to remove the port mapping.
 		 * Try to add it again */
 		listen_data->adding = TRUE;
-		/* TODO: Need to keep track of this return value! */
-		gaim_upnp_set_port_mapping(
-			gaim_network_get_port_from_fd(listen_data->listenfd),
-			(listen_data->socket_type == SOCK_STREAM) ? "TCP" : "UDP",
-			gaim_network_set_upnp_port_mapping_cb, listen_data);
+		listen_data->mapping_data = gaim_upnp_set_port_mapping(
+					gaim_network_get_port_from_fd(listen_data->listenfd),
+					(listen_data->socket_type == SOCK_STREAM) ? "TCP" : "UDP",
+					gaim_network_set_upnp_port_mapping_cb, listen_data);
 		return;
 	}
 
 	if (listen_data->cb)
 		listen_data->cb(listen_data->listenfd, listen_data->cb_data);
 
+	/* Clear the UPnP mapping data, since it's complete and gaim_netweork_listen_cancel() will try to cancel
+	 * it otherwise. */
+	listen_data->mapping_data = NULL;
 	gaim_network_listen_cancel(listen_data);
 }
 
@@ -327,11 +329,10 @@
 	listen_data->cb = cb;
 	listen_data->cb_data = cb_data;
 
-	/* TODO: Need to keep track of this return value! */
-	gaim_upnp_set_port_mapping(
-			gaim_network_get_port_from_fd(listenfd),
-			(socket_type == SOCK_STREAM) ? "TCP" : "UDP",
-			gaim_network_set_upnp_port_mapping_cb, listen_data);
+	listen_data->mapping_data = gaim_upnp_set_port_mapping(
+					gaim_network_get_port_from_fd(listenfd),
+					(socket_type == SOCK_STREAM) ? "TCP" : "UDP",
+					gaim_network_set_upnp_port_mapping_cb, listen_data);
 
 	return listen_data;
 }
@@ -370,6 +371,9 @@
 
 void gaim_network_listen_cancel(GaimNetworkListenData *listen_data)
 {
+	if (listen_data->mapping_data != NULL)
+		gaim_upnp_cancel_port_mapping(listen_data->mapping_data);
+
 	g_free(listen_data);
 }