comparison 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
comparison
equal deleted inserted replaced
15439:a415922e2882 15441:56a2a0bb290a
72 int socket_type; 72 int socket_type;
73 gboolean retry; 73 gboolean retry;
74 gboolean adding; 74 gboolean adding;
75 GaimNetworkListenCallback cb; 75 GaimNetworkListenCallback cb;
76 gpointer cb_data; 76 gpointer cb_data;
77 UPnPMappingAddRemove *mapping_data;
77 }; 78 };
78 79
79 #ifdef HAVE_LIBNM 80 #ifdef HAVE_LIBNM
80 void nm_callback_func(libnm_glib_ctx* ctx, gpointer user_data); 81 void nm_callback_func(libnm_glib_ctx* ctx, gpointer user_data);
81 #endif 82 #endif
208 if (!success) { 209 if (!success) {
209 gaim_debug_info("network", "Couldn't create UPnP mapping\n"); 210 gaim_debug_info("network", "Couldn't create UPnP mapping\n");
210 if (listen_data->retry) { 211 if (listen_data->retry) {
211 listen_data->retry = FALSE; 212 listen_data->retry = FALSE;
212 listen_data->adding = FALSE; 213 listen_data->adding = FALSE;
213 /* TODO: Need to keep track of this return value! */ 214 listen_data->mapping_data = gaim_upnp_remove_port_mapping(
214 gaim_upnp_remove_port_mapping( 215 gaim_network_get_port_from_fd(listen_data->listenfd),
215 gaim_network_get_port_from_fd(listen_data->listenfd), 216 (listen_data->socket_type == SOCK_STREAM) ? "TCP" : "UDP",
216 (listen_data->socket_type == SOCK_STREAM) ? "TCP" : "UDP", 217 gaim_network_set_upnp_port_mapping_cb, listen_data);
217 gaim_network_set_upnp_port_mapping_cb, listen_data);
218 return; 218 return;
219 } 219 }
220 } else if (!listen_data->adding) { 220 } else if (!listen_data->adding) {
221 /* We've tried successfully to remove the port mapping. 221 /* We've tried successfully to remove the port mapping.
222 * Try to add it again */ 222 * Try to add it again */
223 listen_data->adding = TRUE; 223 listen_data->adding = TRUE;
224 /* TODO: Need to keep track of this return value! */ 224 listen_data->mapping_data = gaim_upnp_set_port_mapping(
225 gaim_upnp_set_port_mapping( 225 gaim_network_get_port_from_fd(listen_data->listenfd),
226 gaim_network_get_port_from_fd(listen_data->listenfd), 226 (listen_data->socket_type == SOCK_STREAM) ? "TCP" : "UDP",
227 (listen_data->socket_type == SOCK_STREAM) ? "TCP" : "UDP", 227 gaim_network_set_upnp_port_mapping_cb, listen_data);
228 gaim_network_set_upnp_port_mapping_cb, listen_data);
229 return; 228 return;
230 } 229 }
231 230
232 if (listen_data->cb) 231 if (listen_data->cb)
233 listen_data->cb(listen_data->listenfd, listen_data->cb_data); 232 listen_data->cb(listen_data->listenfd, listen_data->cb_data);
234 233
234 /* Clear the UPnP mapping data, since it's complete and gaim_netweork_listen_cancel() will try to cancel
235 * it otherwise. */
236 listen_data->mapping_data = NULL;
235 gaim_network_listen_cancel(listen_data); 237 gaim_network_listen_cancel(listen_data);
236 } 238 }
237 239
238 240
239 static GaimNetworkListenData * 241 static GaimNetworkListenData *
325 listen_data->adding = TRUE; 327 listen_data->adding = TRUE;
326 listen_data->retry = TRUE; 328 listen_data->retry = TRUE;
327 listen_data->cb = cb; 329 listen_data->cb = cb;
328 listen_data->cb_data = cb_data; 330 listen_data->cb_data = cb_data;
329 331
330 /* TODO: Need to keep track of this return value! */ 332 listen_data->mapping_data = gaim_upnp_set_port_mapping(
331 gaim_upnp_set_port_mapping( 333 gaim_network_get_port_from_fd(listenfd),
332 gaim_network_get_port_from_fd(listenfd), 334 (socket_type == SOCK_STREAM) ? "TCP" : "UDP",
333 (socket_type == SOCK_STREAM) ? "TCP" : "UDP", 335 gaim_network_set_upnp_port_mapping_cb, listen_data);
334 gaim_network_set_upnp_port_mapping_cb, listen_data);
335 336
336 return listen_data; 337 return listen_data;
337 } 338 }
338 339
339 GaimNetworkListenData * 340 GaimNetworkListenData *
368 return ret; 369 return ret;
369 } 370 }
370 371
371 void gaim_network_listen_cancel(GaimNetworkListenData *listen_data) 372 void gaim_network_listen_cancel(GaimNetworkListenData *listen_data)
372 { 373 {
374 if (listen_data->mapping_data != NULL)
375 gaim_upnp_cancel_port_mapping(listen_data->mapping_data);
376
373 g_free(listen_data); 377 g_free(listen_data);
374 } 378 }
375 379
376 unsigned short 380 unsigned short
377 gaim_network_get_port_from_fd(int fd) 381 gaim_network_get_port_from_fd(int fd)