Revision de1d579f1efd330d7acfb5a1a8e8e8957ca3ba54

evands at pidgin.im evands at pidgin.im
Thu Mar 22 08:52:17 EDT 2007


o   -----------------------------------------------------------------
|   Revision: de1d579f1efd330d7acfb5a1a8e8e8957ca3ba54
|   Ancestor: 508b969eb6b11cc64db8eb5e17f1699479731ef3
|   Author: evands at pidgin.im
|   Date: 2007-03-22T12:51:33
|   Branch: im.pidgin.pidgin
|   
|   Modified files:
|           libpurple/nat-pmp.c libpurple/nat-pmp.h libpurple/network.c
|   
|   ChangeLog: 
|   
|   nat-pmp is now functional with a compatible router.  I'm not enabling this code yet because it hasn't been tested with a router which doesn't support nat-pmp.
|   
|   ============================================================
|   --- libpurple/nat-pmp.c	c37ed4dd86f80cd55a504a59332aa75f13b75e55
|   +++ libpurple/nat-pmp.c	b7b50208c7e07447afb75b2f2890bd4dd3b0d91c
|   @@ -52,14 +52,23 @@
|    #include <net/if.h>
|    
|    #ifdef NET_RT_DUMP2
|   +
|   +#define PMP_DEBUG
|   +
|    /*
|     *	Thanks to R. Matthew Emerson for the fixes on this
|     */
|    
|   +#define PMP_MAP_OPCODE_UDP	1
|   +#define PMP_MAP_OPCODE_TCP	2
|   +
|   +#define PMP_VERSION			0
|   +#define PMP_PORT			5351
|   +#define PMP_TIMEOUT			250000	//	250000 useconds
|   +
|    /* alignment constraint for routing socket */
|   -#define ROUNDUP(a)							\
|   -((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
|   -#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
|   +#define ROUNDUP(a)			((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
|   +#define ADVANCE(x, n)		(x += ROUNDUP((n)->sa_len))
|    
|    static void
|    get_rtaddrs(int bitmask, struct sockaddr *sa, struct sockaddr *addrs[])
|   @@ -98,6 +107,9 @@ is_default_route(struct sockaddr *sa, st
|    		return 0;
|    }
|    
|   +/*!
|   + * The return sockaddr_in must be g_free()'d when no longer needed
|   + */
|    static struct sockaddr_in *
|    default_gw()
|    {
|   @@ -106,31 +118,34 @@ default_gw()
|        char *buf, *next, *lim;
|        struct rt_msghdr2 *rtm;
|        struct sockaddr *sa;
|   -    struct sockaddr *rti_info[RTAX_MAX];
|   -	struct sockaddr_in *sin;
|   -	
|   +	struct sockaddr_in *sin = NULL;
|   +	gboolean found = FALSE;
|   +
|        mib[0] = CTL_NET;
|   -    mib[1] = PF_ROUTE;
|   -    mib[2] = 0;
|   -    mib[3] = 0;
|   +    mib[1] = PF_ROUTE; /* entire routing table or a subset of it */
|   +    mib[2] = 0; /* protocol number - always 0 */
|   +    mib[3] = 0; /* address family - 0 for all addres families */
|        mib[4] = NET_RT_DUMP2;
|        mib[5] = 0;
|    	
|   +	/* Determine the buffer side needed to get the full routing table */
|        if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 
|    	{
|   -		err(1, "sysctl: net.route.0.0.dump estimate");
|   +		purple_debug_warning("nat-pmp", "sysctl: net.route.0.0.dump estimate");
|   +		return NULL;
|        }
|    	
|   -    buf = malloc(needed);
|   -	
|   -    if (buf == 0) 
|   +    if (!(buf = malloc(needed)))
|    	{
|   -		err(2, "malloc");
|   +		purple_debug_warning("nat-pmp", "malloc");
|   +		return NULL;
|        }
|    	
|   +	/* Read the routing table into buf */
|        if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 
|    	{
|   -		err(1, "sysctl: net.route.0.0.dump");
|   +		purple_debug_warning("nat-pmp", "sysctl: net.route.0.0.dump");
|   +		return NULL;
|        }
|    	
|        lim = buf + needed;
|   @@ -142,36 +157,51 @@ default_gw()
|    		
|    		if (sa->sa_family == AF_INET) 
|    		{
|   -            sin = (struct sockaddr_in *)sa;
|   -			struct sockaddr addr, mask;
|   -			
|   -			get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
|   -			bzero(&addr, sizeof(addr));
|   -			
|   -			if (rtm->rtm_addrs & RTA_DST)
|   -				bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len);
|   -			
|   -			bzero(&mask, sizeof(mask));
|   -			
|   -			if (rtm->rtm_addrs & RTA_NETMASK)
|   -				bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len);
|   -			
|   -			if (is_default_route(&addr, &mask)) 
|   +			sin = (struct sockaddr_in*) sa;
|   +
|   +			if ((rtm->rtm_flags & RTF_GATEWAY) && sin->sin_addr.s_addr == INADDR_ANY)
|    			{
|   -				sin = (struct sockaddr_in *)rti_info[RTAX_GATEWAY];
|   -				break;
|   +				/* We found the default route. Now get the destination address and netmask. */
|   +	            struct sockaddr *rti_info[RTAX_MAX];
|   +				struct sockaddr addr, mask;
|   +
|   +				get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
|   +				bzero(&addr, sizeof(addr));
|   +				
|   +				if (rtm->rtm_addrs & RTA_DST)
|   +					bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len);
|   +				
|   +				bzero(&mask, sizeof(mask));
|   +				
|   +				if (rtm->rtm_addrs & RTA_NETMASK)
|   +					bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len);
|   +				
|   +				if (rtm->rtm_addrs & RTA_GATEWAY &&
|   +					is_default_route(&addr, &mask)) 
|   +				{					
|   +					if (rti_info[RTAX_GATEWAY]) {
|   +						struct sockaddr_in *rti_sin = (struct sockaddr_in *)rti_info[RTAX_GATEWAY];
|   +						sin = g_new0(struct sockaddr_in, 1);
|   +						sin->sin_family = rti_sin->sin_family;
|   +						sin->sin_port = rti_sin->sin_port;
|   +						sin->sin_addr.s_addr = rti_sin->sin_addr.s_addr;
|   +						memcpy(sin, rti_info[RTAX_GATEWAY], sizeof(struct sockaddr_in));
|   +
|   +						purple_debug_info("nat-pmp", "found a default gateway");
|   +						found = TRUE;
|   +						break;
|   +					}
|   +				}
|    			}
|    		}
|   -		
|   -		rtm = (struct rt_msghdr2 *)next;
|        }
|   -	
|   -    free(buf);
|   -	
|   -	return sin;
|   +
|   +	return (found ? sin : NULL);
|    }
|    
|   -//!	double_timeout(struct timeval *) will handle doubling a timeout for backoffs required by NAT-PMP
|   +/*!
|   + * double_timeout(struct timeval *) will handle doubling a timeout for backoffs required by NAT-PMP
|   + */
|    static void
|    double_timeout(struct timeval *to)
|    {
|   @@ -278,9 +308,11 @@ iterate:
|    		++req_attempts;
|    		double_timeout(&req_timeout);
|    	}
|   -	
|   -	if (publicsockaddr == NULL)
|   +
|   +	if (publicsockaddr == NULL) {
|   +		g_free(gateway);
|    		return NULL;
|   +	}
|    	
|    #ifdef PMP_DEBUG
|    	purple_debug_info("nat-pmp", "Response received from NAT-PMP device:\n");
|   @@ -294,7 +326,9 @@ iterate:
|    #endif	
|    
|    	publicsockaddr->sin_addr.s_addr = resp.address;
|   -	
|   +
|   +	g_free(gateway);
|   +
|    	return inet_ntoa(publicsockaddr->sin_addr);
|    }
|    
|   @@ -302,7 +336,7 @@ pmp_map_response_t *
|     *	will return NULL on error, or a pointer to the pmp_map_response_t type
|     */
|    pmp_map_response_t *
|   -purple_pmp_create_map(uint8_t type, uint16_t privateport, uint16_t publicport, uint32_t lifetime)
|   +purple_pmp_create_map(PurplePmpType type, uint16_t privateport, uint16_t publicport, uint32_t lifetime)
|    {
|    	struct sockaddr_in *gateway = default_gw();
|    	
|   @@ -331,7 +365,7 @@ purple_pmp_create_map(uint8_t type, uint
|    	bzero(&req, sizeof(pmp_map_request_t));
|    	bzero(resp, sizeof(pmp_map_response_t));
|    	req.version = 0;
|   -	req.opcode	= type;	
|   +	req.opcode	= ((type == PURPLE_PMP_TYPE_UDP) ? PMP_MAP_OPCODE_UDP : PMP_MAP_OPCODE_TCP);	
|    	req.privateport = htons(privateport); //	What a difference byte ordering makes...d'oh!
|    	req.publicport = htons(publicport);
|    	req.lifetime = htonl(lifetime);
|   @@ -393,6 +427,8 @@ iterate:
|    	purple_debug_info("nat-pmp", "lifetime: %d\n", ntohl(resp->lifetime));
|    #endif	
|    
|   +	g_free(gateway);
|   +
|    	return resp;
|    }
|    
|   @@ -401,11 +437,13 @@ pmp_map_response_t *
|     *	will return NULL on error, or a pointer to the pmp_map_response_t type
|     */
|    pmp_map_response_t *
|   -purple_pmp_destroy_map(uint8_t type, uint16_t privateport)
|   +purple_pmp_destroy_map(PurplePmpType type, uint16_t privateport)
|    {
|   -	pmp_map_response_t *response = NULL;
|   +	pmp_map_response_t *response;
|    	
|   -	if ((response = purple_pmp_create_map(type, privateport, 0, 0)) == NULL)
|   +	response = purple_pmp_create_map(((type == PURPLE_PMP_TYPE_UDP) ? PMP_MAP_OPCODE_UDP : PMP_MAP_OPCODE_TCP),
|   +							privateport, 0, 0);
|   +	if (!response)
|    	{
|    		purple_debug_info("nat-pmp", "Failed to properly destroy mapping for %d!\n", privateport);
|    		return NULL;
|   @@ -423,13 +461,13 @@ pmp_map_response_t *
|    }
|    
|    pmp_map_response_t *
|   -purple_pmp_create_map(uint8_t type, uint16_t privateport, uint16_t publicport, uint32_t lifetime)
|   +purple_pmp_create_map(PurplePmpType type, uint16_t privateport, uint16_t publicport, uint32_t lifetime)
|    {
|    	return NULL;
|    }
|    
|    pmp_map_response_t *
|   -purple_pmp_destroy_map(uint8_t type, uint16_t privateport)
|   +purple_pmp_destroy_map(PurplePmpType type, uint16_t privateport)
|    {
|    	return NULL;
|    }
|   ============================================================
|   --- libpurple/nat-pmp.h	501125d36575a7a8bcb7e1e18de52391ea57440c
|   +++ libpurple/nat-pmp.h	fde05a571347c5fd3ae9975f2ad0fbe908e10fa2
|   @@ -41,20 +41,19 @@
|    #include <net/if.h>
|    #include <net/route.h>
|    
|   -#define PMP_VERSION		0
|   -#define PMP_PORT		5351
|   -#define PMP_TIMEOUT		250000	//	250000 useconds
|   -#define PMP_LIFETIME	3600	//	3600 seconds
|   +#define PURPLE_PMP_LIFETIME		3600	//	3600 seconds
|    
|   -#define PMP_MAP_UDP		1
|   -#define PMP_MAP_TCP		2
|   -
|    /*
|     *	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;
|   +
|    typedef struct {
|    	uint8_t	version;
|    	uint8_t opcode;
|   @@ -88,7 +87,7 @@ char *purple_pmp_get_public_ip();
|    } pmp_map_response_t;
|    
|    char *purple_pmp_get_public_ip();
|   -pmp_map_response_t *purple_pmp_create_map(uint8_t type, uint16_t privateport, uint16_t publicport, uint32_t lifetime);
|   -pmp_map_response_t *purple_pmp_destroy_map(uint8_t type, uint16_t privateport);
|   +pmp_map_response_t *purple_pmp_create_map(PurplePmpType type, uint16_t privateport, uint16_t publicport, uint32_t lifetime);
|   +pmp_map_response_t *purple_pmp_destroy_map(PurplePmpType type, uint16_t privateport);
|    	
|    #endif
|   ============================================================
|   --- libpurple/network.c	bbb743b65d53f76a80e8e511ff589eafab652e5b
|   +++ libpurple/network.c	f4abab72cf68a07f04246d6c244420ca5ab42363
|   @@ -47,6 +47,8 @@
|    #include "stun.h"
|    #include "upnp.h"
|    
|   +/* #define ENABLE_NAT_PMP */
|   +
|    #ifdef ENABLE_NAT_PMP
|    #include "nat-pmp.h"
|    #endif
|   @@ -79,9 +81,6 @@ struct _PurpleNetworkListenData {
|    	PurpleNetworkListenCallback cb;
|    	gpointer cb_data;
|    	UPnPMappingAddRemove *mapping_data;
|   -#ifdef ENABLE_NAT_PMP
|   -	gboolean has_pmp_mapping;
|   -#endif
|    };
|    
|    #ifdef HAVE_LIBNM
|   @@ -251,7 +250,21 @@ purple_network_set_upnp_port_mapping_cb(
|    	purple_network_listen_cancel(listen_data);
|    }
|    
|   +static gboolean
|   +purple_network_finish_pmp_map_cb(gpointer data)
|   +{
|   +	PurpleNetworkListenData *listen_data;
|   +	
|   +	listen_data = data;
|   +	
|   +	if (listen_data->cb)
|   +		listen_data->cb(listen_data->listenfd, listen_data->cb_data);
|    
|   +	purple_network_listen_cancel(listen_data);
|   +
|   +	return FALSE;
|   +}
|   +
|    static PurpleNetworkListenData *
|    purple_network_do_listen(unsigned short port, int socket_type, PurpleNetworkListenCallback cb, gpointer cb_data)
|    {
|   @@ -348,15 +361,22 @@ purple_network_do_listen(unsigned short 
|    
|    #ifdef ENABLE_NAT_PMP
|    	/* Attempt a NAT-PMP Mapping, which will return immediately */
|   -	listen_data->has_pmp_mapping = (purple_pmp_create_map(((socket_type == SOCK_STREAM) ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP),
|   -														actual_port, actual_port, PURPLE_PMP_LIFETIME) != NULL);	
|   +	if (purple_pmp_create_map(((socket_type == SOCK_STREAM) ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP),
|   +							  actual_port, actual_port, PURPLE_PMP_LIFETIME) != NULL)
|   +	{
|   +		purple_debug_info("network", "Created NAT-PMP mapping on port %i",actual_port);
|   +		/* We want to return listen_data now, and on the next run loop trigger the cb and destroy listen_data */
|   +		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(
|   -					actual_port,
|   -					(socket_type == SOCK_STREAM) ? "TCP" : "UDP",
|   -					purple_network_set_upnp_port_mapping_cb, listen_data);
|   +	{
|   +		/* Attempt a UPnP Mapping */
|   +		listen_data->mapping_data = purple_upnp_set_port_mapping(
|   +						 actual_port,
|   +						 (socket_type == SOCK_STREAM) ? "TCP" : "UDP",
|   +						 purple_network_set_upnp_port_mapping_cb, listen_data);
|   +	}
|    
|    	return listen_data;
|    }
|   @@ -398,12 +418,6 @@ void purple_network_listen_cancel(Purple
|    	if (listen_data->mapping_data != NULL)
|    		purple_upnp_cancel_port_mapping(listen_data->mapping_data);
|    
|   -#ifdef ENABLE_NAT_PMP
|   -	if (listen_data->has_pmp_mapping)
|   -		purple_pmp_destroy_map(((listen_data->socket_type == SOCK_STREAM) ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP),
|   -							 purple_network_get_port_from_fd(listen_data->listenfd));
|   -#endif
|   -
|    	g_free(listen_data);
|    }
|    

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


More information about the Commits mailing list