/* Copyright (C) 2017 Paweł Redman This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "shared.h" #define HASH_MAX 4095 static size_t db_hash(uint32_t ipv4) { // FIXME: Use an academically acclaimed hashing algorithm. return (((ipv4 >> 16) ^ ipv4) * 3137) & HASH_MAX; } db_entry *database[HASH_MAX + 1]; pthread_mutex_t database_mutex = PTHREAD_MUTEX_INITIALIZER; // Returns a pointer to the relevant db_entry (newly created if didn't exist). // This function locks the db_entry's mutex before returning. // Returns NULL if calloc fails. db_entry *db_find(uint32_t ipv4) { size_t hash; db_entry *entry; hash = db_hash(ipv4); pthread_mutex_lock(&database_mutex); eli_for (entry, database[hash], ht_chain) if (entry->ipv4 == ipv4) break; if (!entry) { entry = calloc(1, sizeof(db_entry)); if (!entry) goto out; entry->ipv4 = ipv4; pthread_mutex_init(&entry->mutex, NULL); eli_append(database + hash, entry, ht_chain); } pthread_mutex_lock(&entry->mutex); out: pthread_mutex_unlock(&database_mutex); return entry; } static void destroy_entry(db_entry *entry) { job_t *job, *next; for (job = entry->waiting_jobs; job; job = next) { next = job->waiting_list.next; job_destroy(job); } free(entry); } // Frees all entries and resets the database. void db_destroy(void) { size_t i; db_entry *entry, *next; pthread_mutex_lock(&database_mutex); for (i = 0; i < HASH_MAX; i++) { for (entry = database[i]; entry; entry = next) { next = entry->ht_chain.next; pthread_mutex_lock(&entry->mutex); free(entry->revdns.data); free(entry->whois.data); pthread_mutex_unlock(&entry->mutex); destroy_entry(entry); } database[i] = NULL; } pthread_mutex_unlock(&database_mutex); } void db_invalidate_cached_results(void) { size_t i; db_entry *entry; pthread_mutex_lock(&database_mutex); for (i = 0; i < HASH_MAX; i++) eli_for(entry, database[i], ht_chain) entry->cached_result_valid = false; pthread_mutex_unlock(&database_mutex); }