Like other API in DNS cache, `dns_cache_remove` should check arguements return -EINVAL if any of them is NULL. Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
179 lines
4.2 KiB
C
179 lines
4.2 KiB
C
/*
|
|
* Copyright (c) 2024 Endress+Hauser AG
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/net/dns_resolve.h>
|
|
#include <zephyr/net/net_ip.h>
|
|
#include "dns_cache.h"
|
|
|
|
LOG_MODULE_REGISTER(net_dns_cache, CONFIG_DNS_RESOLVER_LOG_LEVEL);
|
|
|
|
static void dns_cache_clean(struct dns_cache const *cache);
|
|
|
|
int dns_cache_flush(struct dns_cache *cache)
|
|
{
|
|
k_mutex_lock(cache->lock, K_FOREVER);
|
|
for (size_t i = 0; i < cache->size; i++) {
|
|
cache->entries[i].in_use = false;
|
|
}
|
|
k_mutex_unlock(cache->lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dns_cache_add(struct dns_cache *cache, char const *query, struct dns_addrinfo const *addrinfo,
|
|
uint32_t ttl)
|
|
{
|
|
k_timepoint_t closest_to_expiry = sys_timepoint_calc(K_FOREVER);
|
|
size_t index_to_replace = 0;
|
|
bool found_empty = false;
|
|
|
|
if (cache == NULL || query == NULL || addrinfo == NULL || ttl == 0) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (strlen(query) >= CONFIG_DNS_RESOLVER_MAX_QUERY_LEN) {
|
|
NET_WARN("Query string to big to be processed %u >= "
|
|
"CONFIG_DNS_RESOLVER_MAX_QUERY_LEN",
|
|
strlen(query));
|
|
return -EINVAL;
|
|
}
|
|
|
|
k_mutex_lock(cache->lock, K_FOREVER);
|
|
|
|
NET_DBG("Add \"%s\" with TTL %" PRIu32, query, ttl);
|
|
|
|
dns_cache_clean(cache);
|
|
|
|
for (size_t i = 0; i < cache->size; i++) {
|
|
if (!cache->entries[i].in_use) {
|
|
index_to_replace = i;
|
|
found_empty = true;
|
|
break;
|
|
} else if (sys_timepoint_cmp(closest_to_expiry, cache->entries[i].expiry) > 0) {
|
|
index_to_replace = i;
|
|
closest_to_expiry = cache->entries[i].expiry;
|
|
}
|
|
}
|
|
|
|
if (!found_empty) {
|
|
NET_DBG("Overwrite \"%s\"", cache->entries[index_to_replace].query);
|
|
}
|
|
|
|
strncpy(cache->entries[index_to_replace].query, query,
|
|
CONFIG_DNS_RESOLVER_MAX_QUERY_LEN - 1);
|
|
cache->entries[index_to_replace].data = *addrinfo;
|
|
cache->entries[index_to_replace].expiry = sys_timepoint_calc(K_SECONDS(ttl));
|
|
cache->entries[index_to_replace].in_use = true;
|
|
|
|
k_mutex_unlock(cache->lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dns_cache_remove(struct dns_cache *cache, char const *query)
|
|
{
|
|
if (cache == NULL || query == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
NET_DBG("Remove all entries with query \"%s\"", query);
|
|
if (strlen(query) >= CONFIG_DNS_RESOLVER_MAX_QUERY_LEN) {
|
|
NET_WARN("Query string to big to be processed %u >= "
|
|
"CONFIG_DNS_RESOLVER_MAX_QUERY_LEN",
|
|
strlen(query));
|
|
return -EINVAL;
|
|
}
|
|
|
|
k_mutex_lock(cache->lock, K_FOREVER);
|
|
|
|
dns_cache_clean(cache);
|
|
|
|
for (size_t i = 0; i < cache->size; i++) {
|
|
if (cache->entries[i].in_use && strcmp(cache->entries[i].query, query) == 0) {
|
|
cache->entries[i].in_use = false;
|
|
}
|
|
}
|
|
|
|
k_mutex_unlock(cache->lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dns_cache_find(struct dns_cache const *cache, const char *query, enum dns_query_type type,
|
|
struct dns_addrinfo *addrinfo, size_t addrinfo_array_len)
|
|
{
|
|
size_t found = 0;
|
|
sa_family_t family;
|
|
|
|
NET_DBG("Find \"%s\"", query);
|
|
if (cache == NULL || query == NULL || addrinfo == NULL || addrinfo_array_len <= 0) {
|
|
return -EINVAL;
|
|
}
|
|
if (type == DNS_QUERY_TYPE_A) {
|
|
family = AF_INET;
|
|
} else if (type == DNS_QUERY_TYPE_AAAA) {
|
|
family = AF_INET6;
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
if (strlen(query) >= CONFIG_DNS_RESOLVER_MAX_QUERY_LEN) {
|
|
NET_WARN("Query string to big to be processed %u >= "
|
|
"CONFIG_DNS_RESOLVER_MAX_QUERY_LEN",
|
|
strlen(query));
|
|
return -EINVAL;
|
|
}
|
|
|
|
k_mutex_lock(cache->lock, K_FOREVER);
|
|
|
|
dns_cache_clean(cache);
|
|
|
|
for (size_t i = 0; i < cache->size; i++) {
|
|
if (!cache->entries[i].in_use) {
|
|
continue;
|
|
}
|
|
if (strcmp(cache->entries[i].query, query) != 0) {
|
|
continue;
|
|
}
|
|
if (cache->entries[i].data.ai_family != family) {
|
|
continue;
|
|
}
|
|
if (found >= addrinfo_array_len) {
|
|
NET_WARN("Found \"%s\" but not enough space in provided buffer.", query);
|
|
found++;
|
|
} else {
|
|
addrinfo[found] = cache->entries[i].data;
|
|
found++;
|
|
NET_DBG("Found \"%s\"", query);
|
|
}
|
|
}
|
|
|
|
k_mutex_unlock(cache->lock);
|
|
|
|
if (found > addrinfo_array_len) {
|
|
return -ENOSR;
|
|
}
|
|
|
|
if (found == 0) {
|
|
NET_DBG("Could not find \"%s\"", query);
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/* Needs to be called when lock is already acquired */
|
|
static void dns_cache_clean(struct dns_cache const *cache)
|
|
{
|
|
for (size_t i = 0; i < cache->size; i++) {
|
|
if (!cache->entries[i].in_use) {
|
|
continue;
|
|
}
|
|
|
|
if (sys_timepoint_expired(cache->entries[i].expiry)) {
|
|
NET_DBG("Remove \"%s\"", cache->entries[i].query);
|
|
cache->entries[i].in_use = false;
|
|
}
|
|
}
|
|
}
|