Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

results from Boost.Asio resolver differ

I have a canned reproducer invoking boost::asio::ip::tcp::resolver::resolve() on localhost once every 5 seconds. It counts the number of endpoints returned and compares that value against the previous iteration.

#include <boost/asio.hpp>

#include <iostream>

int main(int argc, char *argv[])
{
    if ( argc < 3 ) {
        std::cerr << argv[0] << " host port" << std::endl;
        exit( EXIT_FAILURE );
    }
    const char* host = argv[1];
    const char* service = argv[2];

    boost::asio::io_service io_service;
    boost::asio::ip::tcp::resolver resolver( io_service );

    size_t previous = 0;
    while ( true ) {
        boost::asio::ip::tcp::resolver::iterator i(
                resolver.resolve(
                    boost::asio::ip::tcp::resolver::query( host, service )
                    )
                );
        size_t count( 0 );
        while ( i != boost::asio::ip::tcp::resolver::iterator() ) {
            std::cout << i->endpoint() << std::endl;
            ++i;
            ++count;
        }

        std::cout << "got " << count << " addresses" << std::endl;
        if ( previous == 0 ) {
            previous = count;
        }
        assert( count == previous );

        sleep( 5 );
    }
}

sample session

~> time ./addrinfo_asio localhost 80

...

127.0.0.1:80
got 1 addresses
[::1]:80
127.0.0.1:80
got 2 addresses
addrinfo_asio: addrinfo_asio.cc:35: int main(int, char**): Assertion `count == previous' failed.
Aborted (core dumped)

real    216m20.515s
user    0m0.181s
sys     0m0.193s
~> 

You can see it found one endpoint (127.0.0.1:80) for about 3.5 hours, then found two (127.0.0.1:80 and [::1]:80). I'm wondering

  1. why the endpoint count changes from one, to two?
  2. what could cause it?

Resolving both ipv4 and ipv6 addresses is intentional, I do not want to limit the query to just ipv4. I realize this behavior is likely not specific to asio, I also have a reproducer invoking getaddrinfo directly that exhibits the same behavior. My platform is ppc64 RHEL 6.2 if that is relevant. I have not tried reproducing elsewhere.

like image 479
Sam Miller Avatar asked Jun 12 '12 04:06

Sam Miller


2 Answers

You can limit resolver to IPv4 only:
ip::tcp::resolver::query(ip::tcp::v4(), host, service)

like image 67
Igor R. Avatar answered Sep 30 '22 13:09

Igor R.


If you take a look at Chris Kohlhoff's (the author of asio) presentation on ipv6 and asio at boost con 2011, he does the following trick.

He reorders the list of endpoints so the ipv4 endpoints come first in the list, with the comment "reality check: IPv6 is unlikely to be available yet".

His example code works in the version of asio released in boost 1.47, but it no longer works in the version I am using (asio standalone 1.18.0) due to his habit of constantly changing the asio implementation as the C++ evolves.

Anyway, the following code works in asio 1.18.0 which is included in boost 1.74

auto resolverResults(mResolver.resolve(hostName, serviceName));
std::transform(resolverResults.begin(), resolverResults.end(), std::back_inserter(endpoints), [](const asio::ip::basic_resolver_entry<asio::ip::tcp>& entry) { return entry.endpoint(); });
std::stable_partition(endpoints.begin(), endpoints.end(), [](const asio::ip::tcp::endpoint& endpoint) { return endpoint.protocol() == asio::ip::tcp::v4(); });
auto endpointsWithIP4First = asio::ip::tcp::resolver::results_type::create(endpoints.begin(), endpoints.end(), hostName, serviceName);
like image 33
deltanine Avatar answered Sep 30 '22 14:09

deltanine