NRF7002-DK and DNS resolver

Hello,

I've been evaluating the NRF7002-DK with 2.3.0-rc1 SDK. Although there's almost no documentation on how to use Noridc's WiFi stack (at least I haven't found any), the samples in the SDK were great and I was able to get the scanning, connecting and DHCP working just fine.

Where I faced issues was with DNS host resolution using the getaddrinfo API - it just times out regardless the timeout value I put in configuration. I have a feeling this has to do with the configuration, but I wasn't able to figure this out. Attempting to debug the issue cause stack overflow as the library seem to be 'caught' in the middle of static initialization when VScode stops on 'main()' entry.

I would greatly appreciate any help to unblock the use of getaddrinfo() API. Thank you!

Here's what I have in the prj.conf

# WiFi stack.
CONFIG_WIFI=y
CONFIG_WIFI_NRF700X=y
CONFIG_NET_L2_WIFI_MGMT=y
# WPA Supplicant is required to establish WiFi connection.
CONFIG_WPA_SUPP=y

# Networking stack needed for WiFi to operate.
CONFIG_NET_L2_ETHERNET=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_IPV4=y
CONFIG_NET_UDP=y
CONFIG_NET_TCP=y
CONFIG_NET_SOCKETS_POLL_MAX=10
CONFIG_NET_CONFIG_SETTINGS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y

CONFIG_DNS_RESOLVER=y
CONFIG_DNS_NUM_CONCUR_QUERIES=2
CONFIG_DNS_RESOLVER_LOG_LEVEL_DBG=y
CONFIG_NET_SOCKETS_DNS_TIMEOUT=30000

# SSL?
CONFIG_POSIX_CLOCK=y
CONFIG_ENTROPY_GENERATOR=y

# Buffers.
CONFIG_NET_PKT_RX_COUNT=8
CONFIG_NET_PKT_TX_COUNT=8

# Memories.
CONFIG_NET_TX_STACK_SIZE=4096
CONFIG_NET_RX_STACK_SIZE=4096
CONFIG_NET_MGMT_EVENT_STACK_SIZE=4096

  • I did several runs, and they were quite inconsistent. Most of the times DNS would work, but from now and then it would timeout, especially on the hosts that are not accessed often. That said, the consequent run on the same host would succeed. I tried to increase the timeout without no effect on resolution error rate, but then I added a retry logic... and now it works like a charm in my app.

    Correctly if I am wrong, but with the config I have it the DNS resolution happens over UDP. Then the only explanation I can think of that would induce the above behavior is that sometimes the first packet is lost (radio issues or my wifi setup, can't say), but afterwards things start to work neetly. Here's the log with socket debug enabled:

    [00:00:10.627,838] <inf> wifi: Connected to WiFi network, waiting for dhcp allocation...
    [00:00:10.975,097] <inf> net_dhcpv4: Received: 192.168.6.57
    [00:00:10.975,280] <inf> net_config: IPv4 address: 192.168.6.57
    [00:00:10.975,280] <inf> net_config: Lease time: 11120 seconds
    [00:00:10.975,341] <inf> net_config: Subnet: 255.255.252.0
    [00:00:10.975,433] <inf> net_config: Router: 192.168.4.1
    [00:00:10.976,623] <inf> wifi: DHCP IP address: 192.168.6.57
    [00:00:12.979,064] <wrn> wifi: Failed to resolve www.google.com: err=-5
    [00:00:13.514,526] <inf> wifi: Successfully resolved www.google.com
    [00:00:13.531,677] <inf> wifi: Successfully resolved www.amazon.com
    [00:00:13.550,781] <inf> wifi: Successfully resolved www.yahoo.com
    [00:00:13.550,781] <inf> wifi: All test servers has been successfully resolved
    

  • Hi,

    Previously, you got timeout when both 2.4 GHz and 5 GHz network bands were enabled. With the addition of your retry logic, do you get successful resolution when both network bands are enabled?

    Best regards,
    Dejan

  • Yes, that's right. Previously I tried to introduce a yield timeout of 1-10 seconds before the DNS resolution happens thinking I am accessing the stack too early (though as I wait for DHCP assignment that shouldn't have mattered). But apparently, it's the retries that guarantee the DNS to work. With the first successful resolution, all consequent resolutions work fine.

  • Hi,

    Could you show your retry logic?

    Best regards,
    Dejan

  • Hi Dejan,

    Sorry for the late response. Here's my retry logic:

    static int verify_hostname_resolved(const char* hostname) {
      struct addrinfo* result;
      struct addrinfo hints = {.ai_family = AF_INET, .ai_socktype = SOCK_DGRAM};
      int err = getaddrinfo(hostname, NULL, &hints, &result);
      if (err != 0) {
        return -EIO;
      }
    
      if (result == NULL) {
        return -ENOENT;
      }
    
      /* IPv4 Address. */
      struct sockaddr_in server = {
          .sin_addr = {.s_addr =
                           ((struct sockaddr_in*)result->ai_addr)->sin_addr.s_addr},
          .sin_family = AF_INET,
          .sin_port = htons(80),
      };
    
      /* Free the address. */
      freeaddrinfo(result);
    
      char ipv4_addr[NET_IPV4_ADDR_LEN];
      if (inet_ntop(AF_INET, &server.sin_addr.s_addr, ipv4_addr,
                    sizeof(ipv4_addr))) {
        LOG_INF("Successfully resolved IP address: hostname=%s, ip=%s", hostname,
                ipv4_addr);
        return 0;
      }
    
      return -EAGAIN;
    }
    
    static int verify_dns() {
      const char* dns_test_servers[] = {"www.google.com", "www.amazon.com",
                                        "www.yahoo.com"};
    
      size_t dns_test_retry_count = 10;
      while (dns_test_retry_count-- > 0) {
        bool resolved = true;
        for (size_t i = 0; i < ARRAY_SIZE(dns_test_servers); ++i) {
          int err = verify_hostname_resolved(dns_test_servers[i]);
          if (err) {
            resolved = false;
            LOG_WRN("Failed to resolve %s: err=%d", dns_test_servers[i], err);
            break;
          }
        }
    
        if (resolved) {
          LOG_INF("All test servers has been successfully resolved");
          return 0;
        }
    
        // Sleep for (random) 500ms before trying again.
        k_usleep(500000);
      }
    
      return -ENETDOWN;
    }
    

Related