Corvusoft / restbed

Corvusoft's Restbed framework brings asynchronous RESTful functionality to C++14 applications.
http://www.corvusoft.co.uk
Other
1.92k stars 379 forks source link

ipv6 delay. Maybe ipv4 fallback? #311

Open AmarOk1412 opened 6 years ago

AmarOk1412 commented 6 years ago

Hmm. I got a problem trying to get requests on an ipv6 endpoint which return a non 200 status. I got like a one minute delay before any result.

The code to reproduce is pretty simple:

restbed::Uri uri(ANYIPV6ENDPOINTRETURNING404);
auto request = std::make_shared<restbed::Request>(std::move(uri));
request->set_header("Accept", "*/*");
request->set_header("Host", serverHost_);

auto ret = restbed::Http::async(request, [](const std::shared_ptr<restbed::Request>&,
                                                     const std::shared_ptr<restbed::Response>& reply) {
                                                         std::cout << "RESULT!" << std::endl;
}).get();

If you want: https://51.254.123.96/name/restbedipv6404 will do the job.

Note: replace the ipv6 address by the ipv4 address fix this. For example https://ns.ring.cx/name/restbedipv6404 will directly return the response.

I don't have any idea how to fix this for now. I'll try to dig later.

AmarOk1412 commented 6 years ago

Note: It's not an issue on all platform. For example, on MacOSX it seems to work.

ben-crowhurst commented 6 years ago

Thank when the time is available will dig into this issue. Sounds juicy :D

AmarOk1412 commented 6 years ago

hmm. In fact, this issue is a bit bad. I got this problem this afternoon. And the thing is, it was from a routing problem (ipv6) from Fibre noire (my FAI).

So, the problem is not only for the 404 status, but on all status. The thing is, this issue is only present in Restbed so I leave it open (Firefox fallback in ipv4). I didn't dig enough to know the best thing to do here...

AmarOk1412 commented 6 years ago

Ok. The bottleneck here is asio::async_connect() which iterates over any DNS record (AAAA first). The thing is, if the ipv6 is available but not well resolved, it will resend a SYN request X times (where X = net.ipv4.tcp_syn_retries). On a lot of systems X = 5 or X = 6. So the timeout of each request will be 3 or 4 minutes.

The RFC 6555 describes a better solution (https://tools.ietf.org/html/rfc6555) but is not used by async_connect. So the way to solve this issue is to replace the async_connect in the restbed code to do a dual connect and use the first socket connected.