#include <pthread.h>
#include <string.h>
#include "x509_issuer_cache.h"
static int
x509_issuer_cmp(struct x509_issuer *x1, struct x509_issuer *x2)
{
int pcmp;
if ((pcmp = memcmp(x1->parent_md, x2->parent_md, EVP_MAX_MD_SIZE)) != 0)
return pcmp;
return memcmp(x1->child_md, x2->child_md, EVP_MAX_MD_SIZE);
}
static size_t x509_issuer_cache_count;
static size_t x509_issuer_cache_max = X509_ISSUER_CACHE_MAX;
static RB_HEAD(x509_issuer_tree, x509_issuer) x509_issuer_cache =
RB_INITIALIZER(&x509_issuer_cache);
static TAILQ_HEAD(lruqueue, x509_issuer) x509_issuer_lru =
TAILQ_HEAD_INITIALIZER(x509_issuer_lru);
static pthread_mutex_t x509_issuer_tree_mutex = PTHREAD_MUTEX_INITIALIZER;
RB_PROTOTYPE(x509_issuer_tree, x509_issuer, entry, x509_issuer_cmp);
RB_GENERATE(x509_issuer_tree, x509_issuer, entry, x509_issuer_cmp);
int
x509_issuer_cache_set_max(size_t max)
{
if (pthread_mutex_lock(&x509_issuer_tree_mutex) != 0)
return 0;
x509_issuer_cache_max = max;
(void) pthread_mutex_unlock(&x509_issuer_tree_mutex);
return 1;
}
static void
x509_issuer_cache_free_oldest(void)
{
struct x509_issuer *old;
if (x509_issuer_cache_count == 0)
return;
old = TAILQ_LAST(&x509_issuer_lru, lruqueue);
TAILQ_REMOVE(&x509_issuer_lru, old, queue);
RB_REMOVE(x509_issuer_tree, &x509_issuer_cache, old);
free(old->parent_md);
free(old->child_md);
free(old);
x509_issuer_cache_count--;
}
void
x509_issuer_cache_free(void)
{
if (pthread_mutex_lock(&x509_issuer_tree_mutex) != 0)
return;
while (x509_issuer_cache_count > 0)
x509_issuer_cache_free_oldest();
(void) pthread_mutex_unlock(&x509_issuer_tree_mutex);
}
int
x509_issuer_cache_find(unsigned char *parent_md, unsigned char *child_md)
{
struct x509_issuer candidate, *found;
int ret = -1;
memset(&candidate, 0, sizeof(candidate));
candidate.parent_md = parent_md;
candidate.child_md = child_md;
if (x509_issuer_cache_max == 0)
return -1;
if (pthread_mutex_lock(&x509_issuer_tree_mutex) != 0)
return -1;
if ((found = RB_FIND(x509_issuer_tree, &x509_issuer_cache,
&candidate)) != NULL) {
TAILQ_REMOVE(&x509_issuer_lru, found, queue);
TAILQ_INSERT_HEAD(&x509_issuer_lru, found, queue);
ret = found->valid;
}
(void) pthread_mutex_unlock(&x509_issuer_tree_mutex);
return ret;
}
void
x509_issuer_cache_add(unsigned char *parent_md, unsigned char *child_md,
int valid)
{
struct x509_issuer *new;
if (x509_issuer_cache_max == 0)
return;
if (valid != 0 && valid != 1)
return;
if ((new = calloc(1, sizeof(struct x509_issuer))) == NULL)
return;
if ((new->parent_md = calloc(1, EVP_MAX_MD_SIZE)) == NULL)
goto err;
memcpy(new->parent_md, parent_md, EVP_MAX_MD_SIZE);
if ((new->child_md = calloc(1, EVP_MAX_MD_SIZE)) == NULL)
goto err;
memcpy(new->child_md, child_md, EVP_MAX_MD_SIZE);
new->valid = valid;
if (pthread_mutex_lock(&x509_issuer_tree_mutex) != 0)
goto err;
while (x509_issuer_cache_count >= x509_issuer_cache_max)
x509_issuer_cache_free_oldest();
if (RB_INSERT(x509_issuer_tree, &x509_issuer_cache, new) == NULL) {
TAILQ_INSERT_HEAD(&x509_issuer_lru, new, queue);
x509_issuer_cache_count++;
new = NULL;
}
(void) pthread_mutex_unlock(&x509_issuer_tree_mutex);
err:
if (new != NULL) {
free(new->parent_md);
free(new->child_md);
}
free(new);
return;
}