blob: 9364189f22ea55339263cba1e479d273422cb49c [file] [log] [blame]
/*
* Copyright (c) 2024 Endress+Hauser AG
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/net/dns_resolve.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)
{
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, struct dns_addrinfo *addrinfo,
size_t addrinfo_array_len)
{
size_t found = 0;
NET_DBG("Find \"%s\"", query);
if (cache == NULL || query == NULL || addrinfo == NULL || addrinfo_array_len <= 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);
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 (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;
}
}
}