Hi, attached you'll find another patch that is needed to make OpenVPN compile on Windows. After quite some consideration I have decided to change the implementation for all platforms, as doing this with #ifdef WIN32 would be messy at best.
What the function in question does is "add a 32 bit offset to an IPv6 address" - needed for server IP address calculation and for client pool assignment. The old implementation did so in rounds of 32 bit, but the windows declaration of "struct in6_addr" has no 32bit-accessor in the underlying union... windows has 8 and 16 bit, solaris has 8 and 32 bit, etc., so the only thing available everywhere is "8 bit". The addition stuff is a bit tricky as you need to be able to handle overflows (what's 0x2 + 0xffffffff in 32bit-math?) - but I've actually tested this for the relevant overflow candidates on Linux/i386 and NetBSD/Sparc64 (different word size, different endianness), and also ran random additions on 3 different implementations and compared the results (same!). So I'm sure it works :-) The new function takes about 1.5-1.8x more time, that is, 70usec vs. 40usec on my Atom 330 - and it's only called once per client connect on the server. I'm willing to accept the slowness here to make the code easier to read, and more portable. Samuli has confirmed that it fixes this particular compilation problem on Windows :-) gert -- USENET is *not* the non-clickable part of WWW! //www.muc.de/~gert/ Gert Doering - Munich, Germany g...@greenie.muc.de fax: +49-89-35655025 g...@net.informatik.tu-muenchen.de
From 1e3c114d655f65dfc3528b1d8884a026ba8bad6b Mon Sep 17 00:00:00 2001 From: Gert Doering <g...@greenie.muc.de> List-Post: openvpn-devel@lists.sourceforge.net Date: Sat, 28 May 2011 22:50:40 +0200 Subject: [PATCH] Replace 32-bit-based add_in6_addr() implementation by an 8-bit based one - windows has no 32-bit accessor to the union inside "struct in6_addr", and the 8-bit accessor is the only common denominator across BSD, Solaris, Linux and Windows... Signed-off-by: Gert Doering <g...@greenie.muc.de> --- socket.c | 34 ++++++++++++++++------------------ 1 files changed, 16 insertions(+), 18 deletions(-) diff --git a/socket.c b/socket.c index 6b855c0..7903c26 100644 --- a/socket.c +++ b/socket.c @@ -2619,32 +2619,30 @@ print_in6_addr (struct in6_addr a6, unsigned int flags, struct gc_arena *gc) return BSTR (&out); } +#ifndef UINT8_MAX +# define UINT8_MAX 0xff +#endif + /* add some offset to an ipv6 address - * (add in steps of 32 bits, taking overflow into next round) + * (add in steps of 8 bits, taking overflow into next round) */ -#ifndef s6_addr32 -# ifdef TARGET_SOLARIS -# define s6_addr32 _S6_un._S6_u32 -# else -# define s6_addr32 __u6_addr.__u6_addr32 -# endif -#endif -#ifndef UINT32_MAX -# define UINT32_MAX (4294967295U) -#endif struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add ) { int i; - uint32_t h; - for( i=3; i>=0 && add > 0 ; i-- ) + for( i=15; i>=0 && add > 0 ; i-- ) { - h = ntohl( base.s6_addr32[i] ); - base.s6_addr32[i] = htonl( (h+add) & UINT32_MAX ); - /* 32-bit overrun? - * caveat: can't do "h+add > UINT32_MAX" with 32bit math! + register int carry; + register uint32_t h; + + h = (unsigned char) base.s6_addr[i]; + base.s6_addr[i] = (h+add) & UINT8_MAX; + + /* using explicit carry for the 8-bit additions will catch + * 8-bit and(!) 32-bit overruns nicely */ - add = ( h > UINT32_MAX - add )? 1: 0; + carry = ((h & 0xff) + (add & 0xff)) >> 8; + add = (add>>8) + carry; } return base; } -- 1.7.3.4
pgp0kSVEup3lu.pgp
Description: PGP signature