> Le 28 déc. 2017 à 16:55, Olivier Mascia <o...@integral.be> a écrit :
> 
>> I'll experiment with the fossil code here.  Familiarizing with winhttp.c for 
>> now.
> 
> I haven't yet come to bottom of it, but using IP (IPv4) in the URL (instead 
> of name) changes it all!!  There seem to be a high price paid in resolving 
> the server name on each round trip (from client). This or, due to dual-stack 
> being the norm on Windows, client connections loose time trying IPv6 
> (generally preferred by Windows when DNS reports both AAAA and A records for 
> a name) before falling back to IPv4.
> 
> My test now runs (the network portion, excluding rebuilding metadata and next 
> things) within 50 seconds for all 250 round-trips and 102700 artifacts 
> received. It was close to 1 hour and a half before.
> 
> I'm further analysing http_socket.c (socket_open) following this discovery.

Okay, it revolves around g.fIPv4 which only appears in these lines:

Search "fIPv4" (3 hits in 3 files)
  I:\fossil\src\http_socket.c (1 hit)
        Line 154:   hints.ai_family = g.fIPv4 ? AF_INET : AF_UNSPEC;
  I:\fossil\src\main.c (1 hit)
        Line 159:   int fIPv4;              /* Use only IPv4, not IPv6. --ipv4 
*/
  I:\fossil\src\url.c (1 hit)
        Line 382:   if( find_option("ipv4",0,0) ) g.fIPv4 = 1;

In http_socket.c it is tested to configure hints.ai_family with either AF_INET 
or AF_UNSPEC in order to query for only IPv4 or both IPv6 and IPv4. The server 
name resolution made by the client then returns both IPv6 and IPv4 because I 
didn't mentioned "--ipv4" option anywhere in my commands.  Further, enumerating 
the IPs, the code attempts socket creation *and* connection, trying the next 
returned IP if the connect fails.

Sounds good isn't it?
No. Because the server side never ever initialised a listening socket for 
dual-stack. It listens on IPv4 only. Leading to long pauses from the client 
trying IPv6 connections, unresponding, before trying next one which might 
happen to be IPv4 and reachable.

The server code do initialize its listening socket as this:

    s = socket(AF_INET, SOCK_STREAM, 0);

That (on Windows) gives you an IPv4-limited socket.
To get a proper dual-stack socket, the socket must be created with AF_INET6 
first then setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,...) should be called to 
remove the "only IPv6" attribute from the socket.  See 
https://msdn.microsoft.com/en-us/library/windows/desktop/ms738574(v=vs.85).aspx.

That is not the only thing to do because the test that follows on the validity 
of the IP address would have to be adjusted to take IPv4/IPv6 into account.

So the current situation is simply that when acting as server, fossil.exe setup 
an IPv4-only listening socket, while by default it will attempt dual-stack 
client connections, loosing a huge amount of time re-establishing those 
connections.  Add to this that recent Windows will reorder the IPs returned by 
getaddrinfo() as to list IPv6 first when the OS looks like having proper IPv6 
internet connectivity.

The quick/easy/dirty/temporary fix before completing the proper support 
(server-side) of IPv4+IPv6 would be to simply adjust the hint.ai_family 
initialisation in http_socket.c::socket_open to read:

#ifdef _WIN32
  hints.ai_family = AF_INET;
#else
  hints.ai_family = g.fIPv4 ? AF_INET : AF_UNSPEC;
#endif

It works nicely for me. Perfectly expected performance of a large clone 
(needing 250 round-trips) in about 50 seconds. Either using explicitly IPv4 in 
the URL or, with that patch, the proper DNS name.

I'll see to help with proper Windows dual-stack server socket in January.

-- 
Best Regards, Meilleures salutations, Met vriendelijke groeten,
Olivier Mascia


_______________________________________________
fossil-users mailing list
fossil-users@lists.fossil-scm.org
http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users

Reply via email to