Mercurial > pidgin
diff libpurple/nat-pmp.c @ 15974:1a12ce76c4f4
The network module now registers the signal 'network-configuration-changed' and emits it when a network change is detected via libnm or the win32 network monitor. The UI could also emit this signal if it knows something network.c doesn't. UPnP and NAT-PMP respond to the signal by clearing their IP address caches; changing networks without quitting/relaunching will now lead to the new IP address being (lazily) determined. This commit also enables nat-pmp and adds nat-pmp.[h|c] to the build process; please let me know if there are any problems building, as I only have OS X test machines.
author | Evan Schoenberg <evan.s@dreskin.net> |
---|---|
date | Sat, 31 Mar 2007 20:33:54 +0000 |
parents | 45cbb80bfd54 |
children | 328ae2c041c3 |
line wrap: on
line diff
--- a/libpurple/nat-pmp.c Sat Mar 31 04:36:05 2007 +0000 +++ b/libpurple/nat-pmp.c Sat Mar 31 20:33:54 2007 +0000 @@ -30,6 +30,8 @@ #include "nat-pmp.h" #include "debug.h" +#include "signals.h" +#include "network.h" #include <arpa/inet.h> #include <netinet/in.h> @@ -87,6 +89,20 @@ typedef struct _PurplePmpMapResponse PurplePmpMapResponse; +typedef enum { + PURPLE_PMP_STATUS_UNDISCOVERED = -1, + PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER, + PURPLE_PMP_STATUS_DISCOVERING, + PURPLE_PMP_STATUS_DISCOVERED +} PurpleUPnPStatus; + +typedef struct { + PurpleUPnPStatus status; + gchar *publicip; +} PurplePmpInfo; + +static PurplePmpInfo pmp_info = {PURPLE_PMP_STATUS_UNDISCOVERED, NULL}; + /* * Thanks to R. Matthew Emerson for the fixes on this */ @@ -240,11 +256,32 @@ char * purple_pmp_get_public_ip() { - struct sockaddr_in *gateway = default_gw(); + struct sockaddr_in addr, *gateway, *publicsockaddr = NULL; + struct timeval req_timeout; + socklen_t len; + + PurplePmpIpRequest req; + PurplePmpIpResponse resp; + int sendfd; + + if (pmp_info.status == PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER) + return NULL; + + if ((pmp_info.status == PURPLE_PMP_STATUS_DISCOVERED) && (pmp_info.publicip != NULL)) + { +#ifdef PMP_DEBUG + purple_debug_info("nat-pmp", "Returning cached publicip %s",pmp_info.publicip); +#endif + return pmp_info.publicip; + } + + gateway = default_gw(); if (!gateway) { purple_debug_info("nat-pmp", "Cannot request public IP from a NULL gateway!\n"); + /* If we get a NULL gateway, don't try again next time */ + pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; return NULL; } @@ -252,12 +289,6 @@ if (gateway->sin_port != PMP_PORT) gateway->sin_port = htons(PMP_PORT); - int sendfd; - struct timeval req_timeout; - PurplePmpIpRequest req; - PurplePmpIpResponse resp; - struct sockaddr_in *publicsockaddr = NULL; - req_timeout.tv_sec = 0; req_timeout.tv_usec = PMP_TIMEOUT; @@ -274,20 +305,19 @@ * With the recommended timeout of 0.25 seconds, we're talking 511.5 seconds (8.5 minutes). * * This seems really silly... if this were nonblocking, a couple retries might be in order, but it's not at present. - * XXX Make this nonblocking. */ #ifdef PMP_DEBUG purple_debug_info("nat-pmp", "Attempting to retrieve the public ip address for the NAT device at: %s\n", inet_ntoa(gateway->sin_addr)); purple_debug_info("nat-pmp", "\tTimeout: %ds %dus\n", req_timeout.tv_sec, req_timeout.tv_usec); #endif - struct sockaddr_in addr; - socklen_t len = sizeof(struct sockaddr_in); /* TODO: Non-blocking! */ + if (sendto(sendfd, &req, sizeof(req), 0, (struct sockaddr *)(gateway), sizeof(struct sockaddr)) < 0) { purple_debug_info("nat-pmp", "There was an error sending the NAT-PMP public IP request! (%s)\n", strerror(errno)); g_free(gateway); + pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; return NULL; } @@ -295,16 +325,19 @@ { purple_debug_info("nat-pmp", "There was an error setting the socket's options! (%s)\n", strerror(errno)); g_free(gateway); + pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; return NULL; } /* TODO: Non-blocking! */ + len = sizeof(struct sockaddr_in); if (recvfrom(sendfd, &resp, sizeof(PurplePmpIpResponse), 0, (struct sockaddr *)(&addr), &len) < 0) { if (errno != EAGAIN) { purple_debug_info("nat-pmp", "There was an error receiving the response from the NAT-PMP device! (%s)\n", strerror(errno)); g_free(gateway); + pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; return NULL; } } @@ -315,11 +348,15 @@ { purple_debug_info("nat-pmp", "Response was not received from our gateway! Instead from: %s\n", inet_ntoa(addr.sin_addr)); g_free(gateway); + + pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; return NULL; } if (!publicsockaddr) { g_free(gateway); + + pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; return NULL; } @@ -338,6 +375,10 @@ g_free(gateway); + g_free(pmp_info.publicip); + pmp_info.publicip = g_strdup(inet_ntoa(publicsockaddr->sin_addr)); + pmp_info.status = PURPLE_PMP_STATUS_DISCOVERED; + return inet_ntoa(publicsockaddr->sin_addr); } @@ -458,6 +499,30 @@ return success; } + +static void +purple_pmp_network_config_changed_cb(void *data) +{ + pmp_info.status = PURPLE_PMP_STATUS_UNDISCOVERED; + g_free(pmp_info.publicip); + pmp_info.publicip = NULL; +} + +static void* +purple_pmp_get_handle(void) +{ + static int handle; + + return &handle; +} + +void +purple_pmp_init() +{ + purple_signal_connect(purple_network_get_handle(), "network-configuration-changed", + purple_pmp_get_handle(), PURPLE_CALLBACK(purple_pmp_network_config_changed_cb), + GINT_TO_POINTER(0)); +} #else /* #ifdef NET_RT_DUMP */ char * purple_pmp_get_public_ip() @@ -476,4 +541,10 @@ { return FALSE; } + +void +purple_pmp_init() +{ + +} #endif /* #ifndef NET_RT_DUMP */