Revision 92eebaf666f2e1fc850e295152612d773e764f2c

evands at pidgin.im evands at pidgin.im
Sat Mar 31 16:34:15 EDT 2007


o   -----------------------------------------------------------------
|   Revision: 92eebaf666f2e1fc850e295152612d773e764f2c
|   Ancestor: 5c8fc9e8be1747485235f4be52a2ed3acf9dc62e
|   Author: evands at pidgin.im
|   Date: 2007-03-31T20:33:54
|   Branch: im.pidgin.pidgin
|   
|   Modified files:
|           ChangeLog.API libpurple/Makefile.am libpurple/nat-pmp.c
|           libpurple/nat-pmp.h libpurple/network.c libpurple/network.h
|           libpurple/upnp.c libpurple/upnp.h
|   
|   ChangeLog: 
|   
|   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.
|   
|   ============================================================
|   --- ChangeLog.API	7d5b4a3e76e446081d5930f73284b1973e3a7a45
|   +++ ChangeLog.API	c39013970ce25d0a576e86272b2ae8fea8af2bf5
|   @@ -416,6 +416,7 @@ version 2.0.0:
|    	* "gtkblist-hiding"
|    	* "gtkblist-unhiding"
|    	* "log-displaying"
|   +	* "network-configuration-changed"
|    	* "savedstatus-changed"
|    	* "sendto-extended-menu"
|    	* "uri-handler"
|   ============================================================
|   --- libpurple/Makefile.am	02143704a0dd9f1a16d987b4c722b762c2fb58e6
|   +++ libpurple/Makefile.am	532f08086b6418786f8eb71439ffacf79862f3fa
|   @@ -49,6 +49,7 @@ purple_coresources = \
|    	imgstore.c \
|    	log.c \
|    	mime.c \
|   +	nat-pmp.c \
|    	network.c \
|    	ntlm.c \
|    	notify.c \
|   @@ -99,6 +100,7 @@ purple_coreheaders = \
|    	imgstore.h \
|    	log.h \
|    	mime.h \
|   +	nat-pmp.h \
|    	network.h \
|    	notify.h \
|    	ntlm.h \
|   ============================================================
|   --- libpurple/nat-pmp.c	0cc6b65d22e43ee71a150d303771e55a580a794a
|   +++ libpurple/nat-pmp.c	01a2138d2a57a096d3a42d30395b878476a183f0
|   @@ -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 Pur
|    
|    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 @@ purple_pmp_get_public_ip()
|    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 @@ purple_pmp_get_public_ip()
|    	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 @@ purple_pmp_get_public_ip()
|    	 * 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_pmp_get_public_ip()
|    	{
|    		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_pmp_get_public_ip()
|    	{
|    		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 @@ purple_pmp_get_public_ip()
|    
|    	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 @@ purple_pmp_destroy_map(PurplePmpType typ
|    
|    	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 @@ purple_pmp_destroy_map(PurplePmpType typ
|    {
|    	return FALSE;
|    }
|   +
|   +void
|   +purple_pmp_init()
|   +{
|   +
|   +}
|    #endif /* #ifndef NET_RT_DUMP */
|   ============================================================
|   --- libpurple/nat-pmp.h	5f2cac238513429f0a46ff2bcf9374b5f61270c3
|   +++ libpurple/nat-pmp.h	b2dd434326438e746912ec2093af768d5d0f40e9
|   @@ -36,27 +36,20 @@
|    
|    #define PURPLE_PMP_LIFETIME	3600	/* 3600 seconds */
|    
|   -/*
|   - *	uint8_t:	version, opcodes
|   - *	uint16_t:	resultcode
|   - *	unint32_t:	epoch (seconds since mappings reset)
|   - */
|   -
|    typedef enum {
|    	PURPLE_PMP_TYPE_UDP,
|    	PURPLE_PMP_TYPE_TCP
|    } PurplePmpType;
|    
|    /**
|   - *
|   + * Initialize nat-pmp
|     */
|   +void purple_pmp_init(void);
|    
|   -/*
|   - * TODO: This should probably cache the result of this lookup requests
|   - *       so that subsequent calls to this function do not require a
|   - *       round-trip exchange with the local router.
|   +/**
|   + *
|     */
|   -char *purple_pmp_get_public_ip();
|   +char *purple_pmp_get_public_ip(void);
|    
|    /**
|     * Remove the NAT-PMP mapping for a specified type on a specified port
|   ============================================================
|   --- libpurple/network.c	60335f4bd92f820defa3407a93d944941ae7dc91
|   +++ libpurple/network.c	eb2bd60ce146f635283a73a30a8f825238c68211
|   @@ -42,17 +42,12 @@
|    
|    #include "debug.h"
|    #include "account.h"
|   +#include "nat-pmp.h"
|    #include "network.h"
|    #include "prefs.h"
|    #include "stun.h"
|    #include "upnp.h"
|    
|   -/* #define ENABLE_NAT_PMP 1 */
|   -
|   -#ifdef ENABLE_NAT_PMP
|   -#include "nat-pmp.h"
|   -#endif
|   -
|    /*
|     * Calling sizeof(struct ifreq) isn't always correct on
|     * Mac OS X (and maybe others).
|   @@ -198,12 +193,10 @@ purple_network_get_my_ip(int fd)
|    	if (ip != NULL)
|    	  return ip;
|    
|   -#ifdef ENABLE_NAT_PMP
|    	/* Attempt to get the IP from a NAT device using NAT-PMP */
|    	ip = purple_pmp_get_public_ip();
|    	if (ip != NULL)
|    		return ip;
|   -#endif
|    
|    	/* Just fetch the IP of the local system */
|    	return purple_network_get_local_system_ip(fd);
|   @@ -250,7 +243,6 @@ purple_network_set_upnp_port_mapping_cb(
|    	purple_network_listen_cancel(listen_data);
|    }
|    
|   -#ifdef ENABLE_NAT_PMP
|    static gboolean
|    purple_network_finish_pmp_map_cb(gpointer data)
|    {
|   @@ -265,7 +257,6 @@ purple_network_finish_pmp_map_cb(gpointe
|    
|    	return FALSE;
|    }
|   -#endif
|    
|    static PurpleNetworkListenData *
|    purple_network_do_listen(unsigned short port, int socket_type, PurpleNetworkListenCallback cb, gpointer cb_data)
|   @@ -361,7 +352,6 @@ purple_network_do_listen(unsigned short 
|    	listen_data->cb = cb;
|    	listen_data->cb_data = cb_data;
|    
|   -#ifdef ENABLE_NAT_PMP
|    	/* Attempt a NAT-PMP Mapping, which will return immediately */
|    	if (purple_pmp_create_map(((socket_type == SOCK_STREAM) ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP),
|    							  actual_port, actual_port, PURPLE_PMP_LIFETIME))
|   @@ -371,7 +361,6 @@ purple_network_do_listen(unsigned short 
|    		purple_timeout_add(0, purple_network_finish_pmp_map_cb, listen_data);
|    	}
|    	else
|   -#endif
|    	{
|    		/* Attempt a UPnP Mapping */
|    		listen_data->mapping_data = purple_upnp_set_port_mapping(
|   @@ -508,6 +497,8 @@ static gboolean wpurple_network_change_t
|    
|    	purple_debug_info("network", "Received Network Change Notification. Current network count is %d, previous count was %d.\n", new_count, current_network_count);
|    
|   +	purple_signal_emit(purple_network_get_handle(), "network-configuration-changed", NULL);
|   +
|    	if (new_count > 0 && ui_ops != NULL && ui_ops->network_connected != NULL) {
|    		ui_ops->network_connected();
|    	} else if (new_count == 0 && current_network_count > 0 &&
|   @@ -616,6 +607,8 @@ nm_callback_func(libnm_glib_ctx* ctx, gp
|    	current = libnm_glib_get_network_state(ctx);
|    	purple_debug_info("network","Entering nm_callback_func!\n");
|    
|   +	purple_signal_emit(purple_network_get_handle(), "network-configuration-changed", NULL);
|   +
|    	switch(current)
|    	{
|    	case LIBNM_ACTIVE_NETWORK_CONNECTION:
|   @@ -641,6 +634,14 @@ nm_callback_func(libnm_glib_ctx* ctx, gp
|    }
|    #endif
|    
|   +void *
|   +purple_network_get_handle(void)
|   +{
|   +	static int handle;
|   +	
|   +	return &handle;
|   +}
|   +
|    void
|    purple_network_init(void)
|    {
|   @@ -673,6 +674,12 @@ purple_network_init(void)
|    	if(nm_context)
|    		nm_callback_idx = libnm_glib_register_callback(nm_context, nm_callback_func, NULL, g_main_context_default());
|    #endif
|   +
|   +	purple_signal_register(purple_network_get_handle(), "network-configuration-changed",
|   +						   purple_marshal_VOID, NULL, 0);
|   +	
|   +	purple_pmp_init();
|   +	purple_upnp_init();
|    }
|    
|    void
|   ============================================================
|   --- libpurple/network.h	6f8979bf0ba8b30e517d718148b5365ac3d09700
|   +++ libpurple/network.h	858b42c7c54f71c5f2008e9a66f1c9b6387de90f
|   @@ -197,6 +197,13 @@ gboolean purple_network_is_available(voi
|    gboolean purple_network_is_available(void);
|    
|    /**
|   + * Get the handle for the network system
|   + *
|   + * @return the handle to the network system
|   + */
|   +void *purple_network_get_handle(void);
|   +
|   +/**
|     * Initializes the network subsystem.
|     */
|    void purple_network_init(void);
|   ============================================================
|   --- libpurple/upnp.c	96621a5920d0f7ffc49169a7327f4dc3345d3acc
|   +++ libpurple/upnp.c	f425a77b17efb304f7aa61c8d638d4d575282bb8
|   @@ -24,15 +24,16 @@
|     */
|    #include "internal.h"
|    
|   +#include "upnp.h"
|   +
|    #include "debug.h"
|   -#include "util.h"
|   +#include "eventloop.h"
|   +#include "network.h"
|    #include "proxy.h"
|   +#include "signals.h"
|   +#include "util.h"
|    #include "xmlnode.h"
|   -#include "network.h"
|   -#include "eventloop.h"
|   -#include "upnp.h"
|    
|   -
|    /***************************************************************
|    ** General Defines                                             *
|    ****************************************************************/
|   @@ -1026,3 +1027,32 @@ purple_upnp_remove_port_mapping(unsigned
|    	do_port_mapping_cb(TRUE, ar);
|    	return ar;
|    }
|   +
|   +static void
|   +purple_upnp_network_config_changed_cb(void *data)
|   +{
|   +	/* Reset the control_info to default values */
|   +	control_info.status = PURPLE_UPNP_STATUS_UNDISCOVERED;
|   +	g_free(control_info.control_url);
|   +	control_info.control_url = NULL;
|   +	control_info.service_type[0] = '\0';
|   +	control_info.publicip[0] = '\0';
|   +	control_info.internalip[0] = '\0';
|   +	control_info.lookup_time = 0;
|   +}
|   +
|   +static void*
|   +purple_upnp_get_handle(void)
|   +{
|   +	static int handle;
|   +	
|   +	return &handle;	
|   +}
|   +
|   +void
|   +purple_upnp_init()
|   +{
|   +	purple_signal_connect(purple_network_get_handle(), "network-configuration-changed",
|   +						  purple_upnp_get_handle(), PURPLE_CALLBACK(purple_upnp_network_config_changed_cb),
|   +						  GINT_TO_POINTER(0));		
|   +}
|   ============================================================
|   --- libpurple/upnp.h	528c77de4eda81ff204682df262574a00c3dfec1
|   +++ libpurple/upnp.h	7fc0680c51662700ad6ff20b2b618736c1f0aebe
|   @@ -41,7 +41,14 @@ typedef void (*PurpleUPnPCallback) (gboo
|    
|    typedef void (*PurpleUPnPCallback) (gboolean success, gpointer data);
|    
|   +
|    /**
|   + * Initialize UPnP
|   + */
|   +void purple_upnp_init(void);
|   +
|   +
|   +/**
|     * Sends a discovery request to search for a UPnP enabled IGD that
|     * contains the WANIPConnection service that will allow us to recieve the
|     * public IP address of the IGD, and control it for forwarding ports.

To get the patch for this revision, please do this:
mtn log --last 1 --diffs --from 92eebaf666f2e1fc850e295152612d773e764f2c


More information about the Commits mailing list