Mercurial > pidgin.yaz
comparison libpurple/upnp.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 | 58ff9a0ffce0 |
comparison
equal
deleted
inserted
replaced
15439:a415922e2882 | 15441:56a2a0bb290a |
---|---|
129 gchar service_type[25]; | 129 gchar service_type[25]; |
130 int retry_count; | 130 int retry_count; |
131 gchar *full_url; | 131 gchar *full_url; |
132 } UPnPDiscoveryData; | 132 } UPnPDiscoveryData; |
133 | 133 |
134 typedef struct { | 134 struct _UPnPMappingAddRemove |
135 { | |
135 unsigned short portmap; | 136 unsigned short portmap; |
136 gchar protocol[4]; | 137 gchar protocol[4]; |
137 gboolean add; | 138 gboolean add; |
138 GaimUPnPCallback cb; | 139 GaimUPnPCallback cb; |
139 gpointer cb_data; | 140 gpointer cb_data; |
140 } UPnPMappingAddRemove; | 141 guint tima; /* gaim_timeout_add handle */ |
142 GaimUtilFetchUrlData *gfud; | |
143 }; | |
141 | 144 |
142 static GaimUPnPControlInfo control_info = { | 145 static GaimUPnPControlInfo control_info = { |
143 GAIM_UPNP_STATUS_UNDISCOVERED, | 146 GAIM_UPNP_STATUS_UNDISCOVERED, |
144 NULL, "\0", "\0", "\0", 0}; | 147 NULL, "\0", "\0", "\0", 0}; |
145 | 148 |
664 control_info.status = GAIM_UPNP_STATUS_DISCOVERING; | 667 control_info.status = GAIM_UPNP_STATUS_DISCOVERING; |
665 | 668 |
666 gaim_upnp_discover_send_broadcast(dd); | 669 gaim_upnp_discover_send_broadcast(dd); |
667 } | 670 } |
668 | 671 |
669 static void | 672 static GaimUtilFetchUrlData* |
670 gaim_upnp_generate_action_message_and_send(const gchar* actionName, | 673 gaim_upnp_generate_action_message_and_send(const gchar* actionName, |
671 const gchar* actionParams, GaimUtilFetchUrlCallback cb, | 674 const gchar* actionParams, GaimUtilFetchUrlCallback cb, |
672 gpointer cb_data) | 675 gpointer cb_data) |
673 { | 676 { |
674 | 677 GaimUtilFetchUrlData* gfud; |
675 gchar* soapMessage; | 678 gchar* soapMessage; |
676 gchar* totalSendMessage; | 679 gchar* totalSendMessage; |
677 gchar* pathOfControl; | 680 gchar* pathOfControl; |
678 gchar* addressOfControl; | 681 gchar* addressOfControl; |
679 int port = 0; | 682 int port = 0; |
701 control_info.service_type, actionName, | 704 control_info.service_type, actionName, |
702 strlen(soapMessage), soapMessage); | 705 strlen(soapMessage), soapMessage); |
703 g_free(pathOfControl); | 706 g_free(pathOfControl); |
704 g_free(soapMessage); | 707 g_free(soapMessage); |
705 | 708 |
706 gaim_util_fetch_url_request(control_info.control_url, FALSE, NULL, TRUE, | 709 gfud = gaim_util_fetch_url_request(control_info.control_url, FALSE, NULL, TRUE, |
707 totalSendMessage, TRUE, cb, cb_data); | 710 totalSendMessage, TRUE, cb, cb_data); |
708 | 711 |
709 g_free(totalSendMessage); | 712 g_free(totalSendMessage); |
710 g_free(addressOfControl); | 713 g_free(addressOfControl); |
714 | |
715 return gfud; | |
711 } | 716 } |
712 | 717 |
713 const gchar * | 718 const gchar * |
714 gaim_upnp_get_public_ip() | 719 gaim_upnp_get_public_ip() |
715 { | 720 { |
882 action_params = g_strdup_printf( | 887 action_params = g_strdup_printf( |
883 DELETE_PORT_MAPPING_PARAMS, | 888 DELETE_PORT_MAPPING_PARAMS, |
884 ar->portmap, ar->protocol); | 889 ar->portmap, ar->protocol); |
885 } | 890 } |
886 | 891 |
887 gaim_upnp_generate_action_message_and_send(action_name, | 892 ar->gfud = gaim_upnp_generate_action_message_and_send(action_name, |
888 action_params, done_port_mapping_cb, ar); | 893 action_params, done_port_mapping_cb, ar); |
889 | 894 |
890 g_free(action_params); | 895 g_free(action_params); |
891 return; | 896 return; |
892 } | 897 } |
893 | 898 |
902 { | 907 { |
903 do_port_mapping_cb(FALSE, data); | 908 do_port_mapping_cb(FALSE, data); |
904 return FALSE; | 909 return FALSE; |
905 } | 910 } |
906 | 911 |
907 void | 912 void gaim_upnp_cancel_port_mapping(UPnPMappingAddRemove *ar) |
913 { | |
914 GSList *l; | |
915 | |
916 /* Remove ar from discovery_callbacks if present; it was inserted after a cb. | |
917 * The same cb may be in the list multple times, so be careful to remove the one assocaited with ar. */ | |
918 l = discovery_callbacks; | |
919 while (l) | |
920 { | |
921 if (l->next && (l->next->data == ar)) { | |
922 discovery_callbacks = g_slist_delete_link(discovery_callbacks, l->next); | |
923 discovery_callbacks = g_slist_delete_link(discovery_callbacks, l); | |
924 } | |
925 | |
926 l = l->next; | |
927 } | |
928 | |
929 if (ar->tima > 0) | |
930 gaim_timeout_remove(ar->tima); | |
931 | |
932 if (ar->gfud) | |
933 gaim_util_fetch_url_cancel(ar->gfud); | |
934 | |
935 g_free(ar); | |
936 } | |
937 | |
938 UPnPMappingAddRemove * | |
908 gaim_upnp_set_port_mapping(unsigned short portmap, const gchar* protocol, | 939 gaim_upnp_set_port_mapping(unsigned short portmap, const gchar* protocol, |
909 GaimUPnPCallback cb, gpointer cb_data) | 940 GaimUPnPCallback cb, gpointer cb_data) |
910 { | 941 { |
911 UPnPMappingAddRemove *ar; | 942 UPnPMappingAddRemove *ar; |
912 | 943 |
923 * the internal IP lookup won't be complete */ | 954 * the internal IP lookup won't be complete */ |
924 discovery_callbacks = g_slist_append( | 955 discovery_callbacks = g_slist_append( |
925 discovery_callbacks, do_port_mapping_cb); | 956 discovery_callbacks, do_port_mapping_cb); |
926 discovery_callbacks = g_slist_append( | 957 discovery_callbacks = g_slist_append( |
927 discovery_callbacks, ar); | 958 discovery_callbacks, ar); |
928 return; | 959 return ar; |
929 } | 960 } |
930 | 961 |
931 /* If we haven't had a successful UPnP discovery, check if 5 minutes has | 962 /* If we haven't had a successful UPnP discovery, check if 5 minutes has |
932 * elapsed since the last try, try again */ | 963 * elapsed since the last try, try again */ |
933 if(control_info.status == GAIM_UPNP_STATUS_UNDISCOVERED || | 964 if(control_info.status == GAIM_UPNP_STATUS_UNDISCOVERED || |
934 (control_info.status == GAIM_UPNP_STATUS_UNABLE_TO_DISCOVER | 965 (control_info.status == GAIM_UPNP_STATUS_UNABLE_TO_DISCOVER |
935 && (time(NULL) - control_info.lookup_time) > 300)) { | 966 && (time(NULL) - control_info.lookup_time) > 300)) { |
936 gaim_upnp_discover(do_port_mapping_cb, ar); | 967 gaim_upnp_discover(do_port_mapping_cb, ar); |
937 return; | 968 return ar; |
938 } else if(control_info.status == GAIM_UPNP_STATUS_UNABLE_TO_DISCOVER) { | 969 } else if(control_info.status == GAIM_UPNP_STATUS_UNABLE_TO_DISCOVER) { |
939 if (cb) { | 970 if (cb) { |
940 /* Asynchronously trigger a failed response */ | 971 /* Asynchronously trigger a failed response */ |
941 gaim_timeout_add(10, fire_port_mapping_failure_cb, ar); | 972 ar->tima = gaim_timeout_add(10, fire_port_mapping_failure_cb, ar); |
942 } else { | 973 } else { |
943 /* No need to do anything if nobody expects a response*/ | 974 /* No need to do anything if nobody expects a response*/ |
944 g_free(ar); | 975 g_free(ar); |
976 ar = NULL; | |
945 } | 977 } |
946 return; | 978 return ar; |
947 } | 979 } |
948 | 980 |
949 do_port_mapping_cb(TRUE, ar); | 981 do_port_mapping_cb(TRUE, ar); |
950 } | 982 return ar; |
951 | 983 } |
952 void | 984 |
985 UPnPMappingAddRemove * | |
953 gaim_upnp_remove_port_mapping(unsigned short portmap, const char* protocol, | 986 gaim_upnp_remove_port_mapping(unsigned short portmap, const char* protocol, |
954 GaimUPnPCallback cb, gpointer cb_data) | 987 GaimUPnPCallback cb, gpointer cb_data) |
955 { | 988 { |
956 UPnPMappingAddRemove *ar; | 989 UPnPMappingAddRemove *ar; |
957 | 990 |
966 if(control_info.status == GAIM_UPNP_STATUS_DISCOVERING) { | 999 if(control_info.status == GAIM_UPNP_STATUS_DISCOVERING) { |
967 discovery_callbacks = g_slist_append( | 1000 discovery_callbacks = g_slist_append( |
968 discovery_callbacks, do_port_mapping_cb); | 1001 discovery_callbacks, do_port_mapping_cb); |
969 discovery_callbacks = g_slist_append( | 1002 discovery_callbacks = g_slist_append( |
970 discovery_callbacks, ar); | 1003 discovery_callbacks, ar); |
971 return; | 1004 return ar; |
972 } | 1005 } |
973 | 1006 |
974 /* If we haven't had a successful UPnP discovery, check if 5 minutes has | 1007 /* If we haven't had a successful UPnP discovery, check if 5 minutes has |
975 * elapsed since the last try, try again */ | 1008 * elapsed since the last try, try again */ |
976 if(control_info.status == GAIM_UPNP_STATUS_UNDISCOVERED || | 1009 if(control_info.status == GAIM_UPNP_STATUS_UNDISCOVERED || |
977 (control_info.status == GAIM_UPNP_STATUS_UNABLE_TO_DISCOVER | 1010 (control_info.status == GAIM_UPNP_STATUS_UNABLE_TO_DISCOVER |
978 && (time(NULL) - control_info.lookup_time) > 300)) { | 1011 && (time(NULL) - control_info.lookup_time) > 300)) { |
979 gaim_upnp_discover(do_port_mapping_cb, ar); | 1012 gaim_upnp_discover(do_port_mapping_cb, ar); |
980 return; | 1013 return ar; |
981 } else if(control_info.status == GAIM_UPNP_STATUS_UNABLE_TO_DISCOVER) { | 1014 } else if(control_info.status == GAIM_UPNP_STATUS_UNABLE_TO_DISCOVER) { |
982 if (cb) { | 1015 if (cb) { |
983 /* Asynchronously trigger a failed response */ | 1016 /* Asynchronously trigger a failed response */ |
984 gaim_timeout_add(10, fire_port_mapping_failure_cb, ar); | 1017 ar->tima = gaim_timeout_add(10, fire_port_mapping_failure_cb, ar); |
985 } else { | 1018 } else { |
986 /* No need to do anything if nobody expects a response*/ | 1019 /* No need to do anything if nobody expects a response*/ |
987 g_free(ar); | 1020 g_free(ar); |
1021 ar = NULL; | |
988 } | 1022 } |
989 return; | 1023 return ar; |
990 } | 1024 } |
991 | 1025 |
992 do_port_mapping_cb(TRUE, ar); | 1026 do_port_mapping_cb(TRUE, ar); |
993 } | 1027 return ar; |
1028 } |