forked from espressif/esp-idf
feat(lwip): Added wrapper for getaddrinfo to handle AF_UNSPEC
This commit is contained in:
@@ -141,6 +141,11 @@ if(CONFIG_LWIP_ENABLE)
|
||||
list(APPEND srcs "lwip/src/core/ipv4/acd.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_LWIP_USE_ESP_GETADDRINFO)
|
||||
list(APPEND srcs "apps/netdb/esp_netdb.c")
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT ${target} STREQUAL "linux")
|
||||
# Support for vfs and linker fragments only for target builds
|
||||
set(linker_fragments linker.lf)
|
||||
|
@@ -1215,6 +1215,16 @@ menu "LWIP"
|
||||
It's typically used with CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF
|
||||
which configures a callback to collect the DNS info on esp_netif layer.
|
||||
|
||||
config LWIP_USE_ESP_GETADDRINFO
|
||||
bool "Enable esp_getaddrinfo() instead of lwip_getaddrinfo()"
|
||||
depends on LWIP_IPV4 && LWIP_IPV6
|
||||
default n # Should be "true" by default, causes DNS issues in OpenThread when enabled (IDF-11771)
|
||||
help
|
||||
Use esp_getaddrinfo() for DNS lookups instead of lwip_getaddrinfo().
|
||||
This function correctly handles the AF_UNSPEC flag for resolving
|
||||
both IPv4 and IPv6 addresses. Available only when both IPv4 and IPv6
|
||||
are enabled.
|
||||
|
||||
endmenu # DNS
|
||||
|
||||
config LWIP_BRIDGEIF_MAX_PORTS
|
||||
|
49
components/lwip/apps/netdb/esp_netdb.c
Normal file
49
components/lwip/apps/netdb/esp_netdb.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <netdb.h>
|
||||
|
||||
|
||||
int esp_getaddrinfo(const char *nodename, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
struct addrinfo hints_copy = *hints;
|
||||
struct addrinfo *res4 = NULL, *res6 = NULL;
|
||||
int ret4, ret6;
|
||||
|
||||
if (hints->ai_family == AF_UNSPEC) {
|
||||
// Attempt to get IPv4 addresses
|
||||
hints_copy.ai_family = AF_INET;
|
||||
ret4 = lwip_getaddrinfo(nodename, servname, &hints_copy, &res4);
|
||||
|
||||
// Attempt to get IPv6 addresses
|
||||
hints_copy.ai_family = AF_INET6;
|
||||
ret6 = lwip_getaddrinfo(nodename, servname, &hints_copy, &res6);
|
||||
|
||||
// Handle results
|
||||
if (ret4 != 0 && ret6 != 0) {
|
||||
return ret4; // Both calls failed, return the first error code
|
||||
}
|
||||
|
||||
*res = res4 ? res4 : res6; // Start with the non-NULL result
|
||||
|
||||
if (res4 && res6) {
|
||||
// Append IPv6 list to the end of IPv4 list
|
||||
struct addrinfo *last = res4;
|
||||
while (last->ai_next) {
|
||||
last = last->ai_next;
|
||||
}
|
||||
last->ai_next = res6;
|
||||
}
|
||||
|
||||
return ERR_OK; // Success
|
||||
} else if ((hints->ai_family == AF_INET) || (hints->ai_family == AF_INET6)) {
|
||||
return lwip_getaddrinfo(nodename, servname, hints, res);
|
||||
}
|
||||
|
||||
// Handle unsupported cases
|
||||
return EAI_FAMILY;
|
||||
}
|
39
components/lwip/include/apps/esp_netdb.h
Normal file
39
components/lwip/include/apps/esp_netdb.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ESP_NETDB_H__
|
||||
#define __ESP_NETDB_H__
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Custom getaddrinfo() wrapper for lwIP that handles AF_UNSPEC correctly.
|
||||
*
|
||||
* Resolves both IPv4 and IPv6 addresses when AF_UNSPEC is specified. Works
|
||||
* even if only one protocol (IPv4 or IPv6) is enabled in lwIP. Merges results
|
||||
* if both protocols are available.
|
||||
*
|
||||
* @return 0 on success, or an error code on failure.
|
||||
* - `EAI_FAMILY`: Address family not supported.
|
||||
*
|
||||
* @note Caller must free the result list with freeaddrinfo().
|
||||
*
|
||||
* @see getaddrinfo(), freeaddrinfo()
|
||||
*/
|
||||
#if CONFIG_LWIP_USE_ESP_GETADDRINFO
|
||||
int esp_getaddrinfo(const char *nodename, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __ESP_NETDB_H__
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -8,6 +8,9 @@
|
||||
#include <stddef.h>
|
||||
#include_next "lwip/netdb.h"
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_LWIP_USE_ESP_GETADDRINFO
|
||||
#include_next "esp_netdb.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -20,7 +23,11 @@ static inline struct hostent *gethostbyname(const char *name)
|
||||
static inline void freeaddrinfo(struct addrinfo *ai)
|
||||
{ lwip_freeaddrinfo(ai); }
|
||||
static inline int getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
|
||||
#ifdef CONFIG_LWIP_USE_ESP_GETADDRINFO
|
||||
{ return esp_getaddrinfo(nodename, servname, hints, res); }
|
||||
#else
|
||||
{ return lwip_getaddrinfo(nodename, servname, hints, res); }
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -474,6 +474,8 @@ The number of IP addresses returned by network database APIs such as ``getaddrin
|
||||
|
||||
In the implementation of ``getaddrinfo()``, the canonical name is not available. Therefore, the ``ai_canonname`` field of the first returned ``addrinfo`` structure will always refer to the ``nodename`` argument or a string with the same contents.
|
||||
|
||||
The ``getaddrinfo()`` system call in lwIP within ESP-IDF has a limitation when using ``AF_UNSPEC``, as it defaults to returning only an IPv4 address in dual stack mode. This can cause issues in IPv6-only networks. To handle this, a workaround involves making two sequential calls to ``getaddrinfo()``: the first with AF_INET to query for IPv4 addresses, and the second with AF_INET6 to retrieve IPv6 addresses. To address this, the custom ``esp_getaddrinfo()`` function has been added to the lwIP port layer to handle both IPv4 and IPv6 addresses when AF_UNSPEC is used. The :ref:`CONFIG_LWIP_USE_ESP_GETADDRINFO` option, available when both IPv4 and IPv6 are enabled, controls whether ``esp_getaddrinfo()`` or the default lwIP implementation is used. It is disabled by default.
|
||||
|
||||
Calling ``send()`` or ``sendto()`` repeatedly on a UDP socket may eventually fail with ``errno`` equal to ``ENOMEM``. This failure occurs due to the limitations of buffer sizes in the lower-layer network interface drivers. If all driver transmit buffers are full, the UDP transmission will fail. For applications that transmit a high volume of UDP datagrams and aim to avoid any dropped datagrams by the sender, it is advisable to implement error code checking and employ a retransmission mechanism with a short delay.
|
||||
|
||||
.. only:: esp32
|
||||
|
Reference in New Issue
Block a user