int DomainNamingService::GetServers()

in src/brpc/policy/domain_naming_service.cpp [36:167]


int DomainNamingService::GetServers(const char* dns_name,
                                    std::vector<ServerNode>* servers) {
    servers->clear();
    if (!dns_name) {
        LOG(ERROR) << "dns_name is NULL";
        return -1;
    }

    // Should be enough to hold host name
    char buf[256];
    size_t i = 0;
    for (; i < sizeof(buf) - 1 && dns_name[i] != '\0'
             && dns_name[i] != ':' && dns_name[i] != '/'; ++i) {
        buf[i] = dns_name[i];
    }
    if (i == sizeof(buf) - 1) {
        LOG(ERROR) << "dns_name=`" << dns_name << "' is too long";
        return -1;
    }
    
    buf[i] = '\0';
    int port = _default_port;
    if (dns_name[i] == ':') {
        ++i;
        char* end = NULL;
        port = strtol(dns_name + i, &end, 10);
        if (end == dns_name + i) {
            LOG(ERROR) << "No port after colon in `" << dns_name << '\'';
            return -1;
        } else if (*end != '\0') {
            if (*end != '/') {
                LOG(ERROR) << "Invalid content=`" << end << "' after port="
                           << port << " in `" << dns_name << '\'';
                return -1;
            }
            // Drop path and other stuff.
            RPC_VLOG << "Drop content=`" << end << "' after port=" << port
                     << " in `" << dns_name << '\'';
            // NOTE: Don't ever change *end which is const.
        }
    }
    if (port < 0 || port > 65535) {
        LOG(ERROR) << "Invalid port=" << port << " in `" << dns_name << '\'';
        return -1;
    }

    if (FLAGS_dns_support_ipv6) {
        struct addrinfo hints;
        struct addrinfo* addrResult;
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = AF_INET6;
        hints.ai_socktype = SOCK_DGRAM;
        char portBuf[16];
        snprintf(portBuf, arraysize(portBuf), "%d", port);
        auto ret = getaddrinfo(buf, portBuf, &hints, &addrResult);
        if (!ret) {
            for(auto rp = addrResult; rp != NULL; rp = rp->ai_next) {
                butil::EndPoint point;
                auto ret = butil::sockaddr2endpoint((struct sockaddr_storage*)rp->ai_addr, rp->ai_addrlen, &point);
                if(!ret) {
                    servers->push_back(ServerNode(point, std::string()));
                }
            }

            freeaddrinfo(addrResult);
            return 0;
        } else {
            LOG(WARNING) << "Can't resolve `" << buf << "for ipv6, fallback to ipv4";
            // fallback to ipv4
        }
        
    }

#if defined(OS_MACOSX)
    _aux_buf_len = 0; // suppress unused warning
    // gethostbyname on MAC is thread-safe (with current usage) since the
    // returned hostent is TLS. Check following link for the ref:
    // https://lists.apple.com/archives/darwin-dev/2006/May/msg00008.html
    struct hostent* result = gethostbyname(buf);
    if (result == NULL) {
        LOG(WARNING) << "result of gethostbyname is NULL";
        return -1;
    }
#else
    if (_aux_buf == NULL) {
        _aux_buf_len = 1024;
        _aux_buf.reset(new char[_aux_buf_len]);
    }
    int ret = 0;
    int error = 0;
    struct hostent ent;
    struct hostent* result = NULL;
    do {
        result = NULL;
        error = 0;
        ret = gethostbyname_r(buf, &ent, _aux_buf.get(), _aux_buf_len,
                              &result, &error);
        if (ret != ERANGE) { // _aux_buf is not long enough
            break;
        }
        _aux_buf_len *= 2;
        _aux_buf.reset(new char[_aux_buf_len]);
        RPC_VLOG << "Resized _aux_buf to " << _aux_buf_len
                 << ", dns_name=" << dns_name;
    } while (1);
    if (ret != 0) {
        // `hstrerror' is thread safe under linux
        LOG(WARNING) << "Can't resolve `" << buf << "', return=`" << berror(ret)
                     << "' herror=`" << hstrerror(error) << '\'';
        return -1;
    }
    if (result == NULL) {
        LOG(WARNING) << "result of gethostbyname_r is NULL";
        return -1;
    }
#endif

    //TODO add protocols other than IPv4 supports
    butil::EndPoint point;
    point.port = port;
    for (int i = 0; result->h_addr_list[i] != NULL; ++i) {
        if (result->h_addrtype == AF_INET) {
            // Only fetch IPv4 addresses
            bcopy(result->h_addr_list[i], &point.ip, result->h_length);
            servers->push_back(ServerNode(point, std::string()));
        } else {
            LOG(WARNING) << "Found address of unsupported protocol="
                         << result->h_addrtype;
        }
    }
    return 0;
}