net: sockets: Make sure that getaddrinfo() cannot hang forever
If for some reason the DNS resolver callback is not called properly then make sure that semaphore will not block forever. Fixes #15197 Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
22c9646b97
commit
1897896e97
|
@ -29,6 +29,16 @@ config NET_SOCKETS_POLL_MAX
|
|||
help
|
||||
Maximum number of entries supported for poll() call.
|
||||
|
||||
config NET_SOCKETS_DNS_TIMEOUT
|
||||
int "Timeout value in milliseconds for DNS queries"
|
||||
default 2000
|
||||
range 1000 300000
|
||||
depends on DNS_RESOLVER
|
||||
help
|
||||
This variable specifies time in milliseconds after which DNS
|
||||
query is considered timeout. Minimum timeout is 1 second and
|
||||
maximum timeout is 5 min.
|
||||
|
||||
config NET_SOCKETS_SOCKOPT_TLS
|
||||
bool "Enable TCP TLS socket option support [EXPERIMENTAL]"
|
||||
select TLS_CREDENTIALS
|
||||
|
|
|
@ -79,6 +79,19 @@ static void dns_resolve_cb(enum dns_resolve_status status,
|
|||
state->idx++;
|
||||
}
|
||||
|
||||
static int exec_query(const char *host, int family,
|
||||
struct getaddrinfo_state *ai_state)
|
||||
{
|
||||
enum dns_query_type qtype = DNS_QUERY_TYPE_A;
|
||||
|
||||
if (IS_ENABLED(CONFIG_NET_IPV6) && family != AF_INET) {
|
||||
qtype = DNS_QUERY_TYPE_AAAA;
|
||||
}
|
||||
|
||||
return dns_get_addr_info(host, qtype, NULL,
|
||||
dns_resolve_cb, ai_state,
|
||||
CONFIG_NET_SOCKETS_DNS_TIMEOUT);
|
||||
}
|
||||
|
||||
int z_impl_z_zsock_getaddrinfo_internal(const char *host, const char *service,
|
||||
const struct zsock_addrinfo *hints,
|
||||
|
@ -111,43 +124,31 @@ int z_impl_z_zsock_getaddrinfo_internal(const char *host, const char *service,
|
|||
/* Link entries in advance */
|
||||
ai_state.ai_arr[0].ai_next = &ai_state.ai_arr[1];
|
||||
|
||||
/* Execute if AF_UNSPEC or AF_INET4 */
|
||||
if (family != AF_INET6) {
|
||||
ret = dns_get_addr_info(host, DNS_QUERY_TYPE_A, NULL,
|
||||
dns_resolve_cb, &ai_state, 1000);
|
||||
if (ret == 0) {
|
||||
k_sem_take(&ai_state.sem, K_FOREVER);
|
||||
st1 = ai_state.status;
|
||||
} else {
|
||||
errno = -ret;
|
||||
st1 = DNS_EAI_SYSTEM;
|
||||
ret = exec_query(host, family, &ai_state);
|
||||
if (ret == 0) {
|
||||
/* If the DNS query for reason fails so that the
|
||||
* dns_resolve_cb() would not be called, then we want the
|
||||
* semaphore to timeout so that we will not hang forever.
|
||||
* So make the sem timeout longer than the DNS timeout so that
|
||||
* we do not need to start to cancel any pending DNS queries.
|
||||
*/
|
||||
int ret = k_sem_take(&ai_state.sem,
|
||||
CONFIG_NET_SOCKETS_DNS_TIMEOUT +
|
||||
K_MSEC(100));
|
||||
if (ret == -EAGAIN) {
|
||||
return DNS_EAI_AGAIN;
|
||||
}
|
||||
|
||||
if (ai_state.idx > 0) {
|
||||
ai_addr = &ai_state.ai_arr[ai_state.idx - 1]._ai_addr;
|
||||
net_sin(ai_addr)->sin_port = htons(port);
|
||||
}
|
||||
st1 = ai_state.status;
|
||||
} else {
|
||||
errno = -ret;
|
||||
st1 = DNS_EAI_SYSTEM;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_IPV6)
|
||||
/* Execute if AF_UNSPEC or AF_INET6 */
|
||||
if (family != AF_INET) {
|
||||
ret = dns_get_addr_info(host, DNS_QUERY_TYPE_AAAA, NULL,
|
||||
dns_resolve_cb, &ai_state, 1000);
|
||||
if (ret == 0) {
|
||||
k_sem_take(&ai_state.sem, K_FOREVER);
|
||||
st2 = ai_state.status;
|
||||
} else {
|
||||
errno = -ret;
|
||||
st2 = DNS_EAI_SYSTEM;
|
||||
}
|
||||
|
||||
if (ai_state.idx > 0) {
|
||||
ai_addr = &ai_state.ai_arr[ai_state.idx - 1]._ai_addr;
|
||||
net_sin6(ai_addr)->sin6_port = htons(port);
|
||||
}
|
||||
if (ai_state.idx > 0) {
|
||||
ai_addr = &ai_state.ai_arr[ai_state.idx - 1]._ai_addr;
|
||||
net_sin(ai_addr)->sin_port = htons(port);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If both attempts failed, it's error */
|
||||
if (st1 && st2) {
|
||||
|
|
Loading…
Reference in New Issue