/* * Copyright (c) 2024 Endress+Hauser AG * * SPDX-License-Identifier: Apache-2.0 */ #include #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; } } }