Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit db04a2bd authored by Mike Yu's avatar Mike Yu
Browse files

Retry binding sockets in DNSResponder if errno is EADDRNOTAVAIL

Tests fail in DNSResponder::startServer() when DNSResponder is binding
the socket while the address is still being set up. This change provides
a simple fix to address this problem because the tests are unaware of
onInterfaceAddressUpdated.

Below is a real failure log:

// device log
04-22 00:29:07.854  root   802   802 I netd    : interfaceAddAddress("testtun10002", "2001:db8:2::202", 128) <1.51ms>
04-22 00:29:07.855  root  6745  6745 E DNSResponder: failed to bind UDP 2001:db8:2::202:53: Cannot assign requested address

// dumpsys netd
04-22 00:29:07.857 onInterfaceAddressUpdated(2001:db8:2::202/128, testtun10002, 128, 0) (0.04ms)

Bug: 186181084
Bug: 175269391
Test: run ResolverMultinetworkTest.GetAddrInfo_AI_ADDRCONFIG 100 times
Change-Id: I8e8824c9056bd298e0e689adfbc720abaa45fcd4
parent 82ae84b9
Loading
Loading
Loading
Loading
+31 −1
Original line number Diff line number Diff line
@@ -36,13 +36,16 @@
#define LOG_TAG "DNSResponder"
#include <android-base/logging.h>
#include <android-base/strings.h>
#include <netdutils/BackoffSequence.h>
#include <netdutils/InternetAddresses.h>
#include <netdutils/Slice.h>
#include <netdutils/SocketOption.h>

using android::netdutils::BackoffSequence;
using android::netdutils::enableSockopt;
using android::netdutils::ScopedAddrinfo;
using android::netdutils::Slice;
using std::chrono::milliseconds;

namespace test {

@@ -71,6 +74,33 @@ std::string addr2str(const sockaddr* sa, socklen_t sa_len) {
    return std::string();
}

// Because The address might still being set up (b/186181084), This is a wrapper function
// that retries bind() if errno is EADDRNOTAVAIL
int bindSocket(int socket, const sockaddr* address, socklen_t address_len) {
    // Set the wrapper to try bind() at most 6 times with backoff time
    // (100 ms, 200 ms, ..., 1600 ms).
    auto backoff = BackoffSequence<milliseconds>::Builder()
                           .withInitialRetransmissionTime(milliseconds(100))
                           .withMaximumRetransmissionCount(5)
                           .build();

    while (true) {
        int ret = bind(socket, address, address_len);
        if (ret == 0 || errno != EADDRNOTAVAIL) {
            return ret;
        }

        if (!backoff.hasNextTimeout()) break;

        LOG(WARNING) << "Retry to bind " << addr2str(address, address_len);
        std::this_thread::sleep_for(backoff.getNextTimeout());
    }

    // Set errno before return since it might have been changed somewhere.
    errno = EADDRNOTAVAIL;
    return -1;
}

/* DNS struct helpers */

const char* dnstype2str(unsigned dnstype) {
@@ -1206,7 +1236,7 @@ android::base::unique_fd DNSResponder::createListeningSocket(int socket_type) {
        const std::string host_str = addr2str(ai->ai_addr, ai->ai_addrlen);
        const char* socket_str = (socket_type == SOCK_STREAM) ? "TCP" : "UDP";

        if (bind(fd.get(), ai->ai_addr, ai->ai_addrlen)) {
        if (bindSocket(fd.get(), ai->ai_addr, ai->ai_addrlen)) {
            PLOG(ERROR) << "failed to bind " << socket_str << " " << host_str << ":"
                        << listen_service_;
            continue;