/* * Copyright (c) 2017 Linaro Limited * * SPDX-License-Identifier: Apache-2.0 */ #if defined(CONFIG_NET_DEBUG_SOCKETS) #define SYS_LOG_DOMAIN "net/sock" #define NET_LOG_ENABLED 1 #endif /* libc headers */ #include /* Zephyr headers */ #include #include struct getaddrinfo_state { const struct zsock_addrinfo *hints; struct k_sem sem; int status; int idx; }; static struct zsock_addrinfo ai_arr[2]; static struct getaddrinfo_state ai_state; static void dns_resolve_cb(enum dns_resolve_status status, struct dns_addrinfo *info, void *user_data) { struct getaddrinfo_state *state = user_data; struct zsock_addrinfo *ai = ai_arr + state->idx; int socktype = SOCK_STREAM; int proto; NET_DBG("dns status: %d", status); if (info == NULL) { if (status == DNS_EAI_ALLDONE) { status = 0; } state->status = status; k_sem_give(&state->sem); return; } memcpy(&ai->_ai_addr, &info->ai_addr, info->ai_addrlen); ai->ai_addr = &ai->_ai_addr; ai->ai_addrlen = info->ai_addrlen; memcpy(&ai->_ai_canonname, &info->ai_canonname, sizeof(ai->_ai_canonname)); ai->ai_canonname = ai->_ai_canonname; ai->ai_family = info->ai_family; if (state->hints) { if (state->hints->ai_socktype) { socktype = state->hints->ai_socktype; } } proto = IPPROTO_TCP; if (socktype == SOCK_DGRAM) { proto = IPPROTO_UDP; } ai->ai_socktype = socktype; ai->ai_protocol = proto; state->idx++; } int zsock_getaddrinfo(const char *host, const char *service, const struct zsock_addrinfo *hints, struct zsock_addrinfo **res) { int family = AF_UNSPEC; long int port; int st1 = DNS_EAI_ADDRFAMILY, st2 = DNS_EAI_ADDRFAMILY; if (hints) { family = hints->ai_family; } port = strtol(service, NULL, 10); if (port < 1 || port > 65535) { return DNS_EAI_NONAME; } ai_state.hints = hints; ai_state.idx = 0; k_sem_init(&ai_state.sem, 0, UINT_MAX); /* Link entries in advance */ ai_arr[0].ai_next = &ai_arr[1]; /* Execute if AF_UNSPEC or AF_INET4 */ if (family != AF_INET6) { dns_get_addr_info(host, DNS_QUERY_TYPE_A, NULL, dns_resolve_cb, &ai_state, 1000); k_sem_take(&ai_state.sem, K_FOREVER); net_sin(&ai_arr[ai_state.idx - 1]._ai_addr)->sin_port = htons(port); st1 = ai_state.status; } /* Execute if AF_UNSPEC or AF_INET6 */ if (family != AF_INET) { dns_get_addr_info(host, DNS_QUERY_TYPE_AAAA, NULL, dns_resolve_cb, &ai_state, 1000); k_sem_take(&ai_state.sem, K_FOREVER); net_sin6(&ai_arr[ai_state.idx - 1]._ai_addr)->sin6_port = htons(port); st2 = ai_state.status; } /* If both attempts failed, it's error */ if (st1 && st2) { if (st1 != DNS_EAI_ADDRFAMILY) { return st1; } return st2; } /* Mark entry as last */ ai_arr[ai_state.idx - 1].ai_next = NULL; *res = ai_arr; return 0; }