/*
* Copyright (c) 2019 Clementine Computing LLC.
*
* This file is part of PopuFare.
*
* PopuFare is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PopuFare 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with PopuFare. If not, see .
*
*/
#include "passdb_slim.h"
// SHALLOW COPY
// passdb_slim_config is a shallow container. All memory management
// should be done from ctx.
//
void passdb_slim_copy_config( passdb_slim_config *cfg, passdb_slim_context *ctx )
{
cfg->hash_modulus = ctx->hash_modulus;
cfg->n_one_cred_bank = ctx->n_one_cred_bank;
cfg->n_two_cred_bank = ctx->n_two_cred_bank;
cfg->n_spillover_bank = ctx->n_spillover_bank;
cfg->n_one_cred_bank_size = ctx->n_one_cred_bank_size;
cfg->n_two_cred_bank_size = ctx->n_two_cred_bank_size;
cfg->n_spillover_bank_size = ctx->n_spillover_bank_size;
cfg->n_one_cred_max_bank = ctx->n_one_cred_max_bank;
cfg->n_two_cred_max_bank = ctx->n_two_cred_max_bank;
cfg->n_spillover_max_bank = ctx->n_spillover_max_bank;
cfg->one_cred_db_base_fn = ctx->one_cred_db_base_fn;
cfg->two_cred_db_base_fn = ctx->two_cred_db_base_fn;
cfg->spillover_db_base_fn = ctx->spillover_db_base_fn;
cfg->db_fn_suffix = ctx->db_fn_suffix;
cfg->ruleparam_db_fn = ctx->ruleparam_db_fn;
cfg->high_watermark_threshold = ctx->high_watermark_threshold;
cfg->low_watermark_threshold = ctx->low_watermark_threshold;
}
#define DEFAULT_HASH_MODULUS 131101
#define DEFAULT_ONE_CRED_MAX_BANK 25
#define DEFAULT_TWO_CRED_MAX_BANK 25
#define DEFAULT_SPILLOVER_MAX_BANK 25
#define DEFAULT_ONE_CRED_BANK_SIZE 10012
#define DEFAULT_TWO_CRED_BANK_SIZE 10012
#define DEFAULT_SPILLOVER_BANK_SIZE 32
#define DEFAULT_ONE_CRED_BANK 1
#define DEFAULT_TWO_CRED_BANK 1
#define DEFAULT_SPILLOVER_BANK 1
#define DEFAULT_ONE_CRED_DB_BASE DATABASE_FILE_PATH "passes_one_bank"
#define DEFAULT_TWO_CRED_DB_BASE DATABASE_FILE_PATH "passes_two_bank"
#define DEFAULT_SPILLOVER_DB_BASE DATABASE_FILE_PATH "passes_spillover_bank"
#define DEFAULT_DB_SUFFIX ".mem"
#define DEFAULT_RULEPARAM_DB DATABASE_FILE_PATH "ruleparam.db"
#define DEFAULT_HIGH_WATERMARK 0.95
//unused
//
#define DEFAULT_LOW_WATERMARK 0.25
int make_default_config( char *config_fn )
{
FILE *fp;
struct tm tm_tim;
struct timeval timval;
char str_tim[FN_SZ];
gettimeofday(&timval, NULL);
localtime_r(&(timval.tv_sec), &tm_tim);
asctime_r(&tm_tim, str_tim);
fp = fopen(config_fn, "w");
if (!fp)
return -1;
fprintf(fp, "# %s", str_tim );
fprintf(fp, "#\n");
fprintf(fp, "#\n");
fprintf(fp, "hash_modulus %i\n", DEFAULT_HASH_MODULUS);
fprintf(fp, "\n");
fprintf(fp, "n_one_cred_max_bank %i\n", DEFAULT_ONE_CRED_MAX_BANK );
fprintf(fp, "n_two_cred_max_bank %i\n", DEFAULT_TWO_CRED_MAX_BANK );
fprintf(fp, "n_spillover_max_bank %i\n", DEFAULT_SPILLOVER_MAX_BANK );
fprintf(fp, "\n");
fprintf(fp, "n_one_cred_bank_size %i\n", DEFAULT_ONE_CRED_BANK_SIZE );
fprintf(fp, "n_two_cred_bank_size %i\n", DEFAULT_TWO_CRED_BANK_SIZE );
fprintf(fp, "n_spillover_bank_size %i\n", DEFAULT_SPILLOVER_BANK_SIZE );
fprintf(fp, "\n");
fprintf(fp, "n_one_cred_bank %i\n", DEFAULT_ONE_CRED_BANK );
fprintf(fp, "n_two_cred_bank %i\n", DEFAULT_TWO_CRED_BANK );
fprintf(fp, "n_spillover_bank %i\n", DEFAULT_SPILLOVER_BANK );
fprintf(fp, "\n");
fprintf(fp, "one_cred_db_base %s\n", DEFAULT_ONE_CRED_DB_BASE );
fprintf(fp, "two_cred_db_base %s\n", DEFAULT_TWO_CRED_DB_BASE );
fprintf(fp, "spillover_db_base %s\n", DEFAULT_SPILLOVER_DB_BASE );
fprintf(fp, "\n");
fprintf(fp, "db_suffix %s\n", DEFAULT_DB_SUFFIX );
fprintf(fp, "\n");
fprintf(fp, "ruleparam_db %s\n", DEFAULT_RULEPARAM_DB );
fprintf(fp, "\n");
fprintf(fp, "high_watermark_threshold %f\n", DEFAULT_HIGH_WATERMARK );
fprintf(fp, "low_watermark_threshold %f\n", DEFAULT_LOW_WATERMARK );
fprintf(fp, "\n");
fclose(fp);
return 0;
}
int save_config( passdb_slim_config *cfg, char *config_fn )
{
FILE *fp;
struct tm tm_tim;
struct timeval timval;
char str_tim[FN_SZ];
gettimeofday(&timval, NULL);
localtime_r(&(timval.tv_sec), &tm_tim);
asctime_r(&tm_tim, str_tim);
fp = fopen( config_fn, "w" );
if (!fp)
{
//DEBUG
//fprintf(stderr, "ERROR: passdb.save_config: could not open file %s\n", config_fn);
//exit(1);
perror(config_fn);
return -1;
}
fprintf(fp, "# %s", str_tim );
fprintf(fp, "#\n");
fprintf(fp, "#\n");
fprintf(fp, "hash_modulus %i\n", cfg->hash_modulus);
fprintf(fp, "\n");
fprintf(fp, "n_one_cred_max_bank %i\n", cfg->n_one_cred_max_bank);
fprintf(fp, "n_two_cred_max_bank %i\n", cfg->n_two_cred_max_bank);
fprintf(fp, "n_spillover_max_bank %i\n", cfg->n_spillover_max_bank);
fprintf(fp, "\n");
fprintf(fp, "n_one_cred_bank_size %i\n", cfg->n_one_cred_bank_size);
fprintf(fp, "n_two_cred_bank_size %i\n", cfg->n_two_cred_bank_size);
fprintf(fp, "n_spillover_bank_size %i\n", cfg->n_spillover_bank_size);
fprintf(fp, "\n");
fprintf(fp, "n_one_cred_bank %i\n", cfg->n_one_cred_bank);
fprintf(fp, "n_two_cred_bank %i\n", cfg->n_two_cred_bank);
fprintf(fp, "n_spillover_bank %i\n", cfg->n_spillover_bank);
fprintf(fp, "\n");
fprintf(fp, "one_cred_db_base %s\n", cfg->one_cred_db_base_fn);
fprintf(fp, "two_cred_db_base %s\n", cfg->two_cred_db_base_fn);
fprintf(fp, "spillover_db_base %s\n", cfg->spillover_db_base_fn);
fprintf(fp, "\n");
fprintf(fp, "db_suffix %s\n", cfg->db_fn_suffix);
fprintf(fp, "\n");
fprintf(fp, "ruleparam_db %s\n", cfg->ruleparam_db_fn);
fprintf(fp, "\n");
fprintf(fp, "high_watermark_threshold %f\n", (double)cfg->high_watermark_threshold );
fprintf(fp, "low_watermark_threshold %f\n", (double)cfg->low_watermark_threshold );
fprintf(fp, "\n");
fclose(fp);
return 0;
}
int read_config( passdb_slim_config *cfg, char *config_fn )
{
FILE *fp;
char buf[FN_SZ];
char keyword[FN_SZ], rvalue[FN_SZ];
int r;
cfg->hash_modulus = -1;
cfg->n_one_cred_bank_size = -1;
cfg->n_two_cred_bank_size = -1;
cfg->n_spillover_bank_size = -1;
cfg->n_one_cred_bank = -1;
cfg->n_two_cred_bank = -1;
cfg->n_spillover_bank = -1;
cfg->one_cred_db_base_fn = NULL;
cfg->two_cred_db_base_fn = NULL;
cfg->spillover_db_base_fn = NULL;
cfg->db_fn_suffix = NULL;
cfg->high_watermark_threshold = 0.99;
cfg->low_watermark_threshold = 0.1;
cfg->ruleparam_db_fn = NULL;
fp = fopen(config_fn, "r");
if (!fp)
return -1;
while ( fgets(buf, FN_SZ-1, fp) )
{
if (buf[0] == '#')
continue;
r = sscanf(buf, "%s %s", keyword, rvalue);
if (keyword[0] == '#')
continue;
if (r!=2)
continue;
if ( strncmp(keyword, "hash_modulus", FN_SZ-1) == 0 )
{
cfg->hash_modulus = atoi(rvalue);
}
else if (strncmp(keyword, "n_one_cred_bank_size", FN_SZ-1) == 0 )
{
cfg->n_one_cred_bank_size = atoi(rvalue);
}
else if (strncmp(keyword, "n_two_cred_bank_size", FN_SZ-1) == 0 )
{
cfg->n_two_cred_bank_size = atoi(rvalue);
}
else if (strncmp(keyword, "n_spillover_bank_size", FN_SZ-1) == 0 )
{
cfg->n_spillover_bank_size = atoi(rvalue);
}
else if (strncmp(keyword, "n_one_cred_bank", FN_SZ-1) == 0 )
{
cfg->n_one_cred_bank = atoi(rvalue);
}
else if (strncmp(keyword, "n_two_cred_bank", FN_SZ-1) == 0 )
{
cfg->n_two_cred_bank = atoi(rvalue);
}
else if (strncmp(keyword, "n_spillover_bank", FN_SZ-1) == 0 )
{
cfg->n_spillover_bank = atoi(rvalue);
}
else if (strncmp(keyword, "n_one_cred_max_bank", FN_SZ-1) == 0 )
{
cfg->n_one_cred_max_bank = atoi(rvalue);
}
else if (strncmp(keyword, "n_two_cred_max_bank", FN_SZ-1) == 0 )
{
cfg->n_two_cred_max_bank = atoi(rvalue);
}
else if (strncmp(keyword, "n_spillover_max_bank", FN_SZ-1) == 0 )
{
cfg->n_spillover_max_bank = atoi(rvalue);
}
else if (strncmp(keyword, "one_cred_db_base", FN_SZ-1) == 0)
{
cfg->one_cred_db_base_fn = strdup(rvalue);
}
else if (strncmp(keyword, "two_cred_db_base", FN_SZ-1) == 0)
{
cfg->two_cred_db_base_fn = strdup(rvalue);
}
else if (strncmp(keyword, "spillover_db_base", FN_SZ-1) == 0)
{
cfg->spillover_db_base_fn = strdup(rvalue);
}
else if (strncmp(keyword, "db_suffix", FN_SZ-1) == 0)
{
cfg->db_fn_suffix = strdup(rvalue);
}
else if (strncmp(keyword, "ruleparam_db", FN_SZ-1) == 0)
{
cfg->ruleparam_db_fn = strdup(rvalue);
}
else if (strncmp(keyword, "high_watermark_threshold", FN_SZ-1) == 0)
{
cfg->high_watermark_threshold = atof(rvalue);
}
else if (strncmp(keyword, "low_watermark_threshold", FN_SZ-1) == 0)
{
cfg->low_watermark_threshold = atof(rvalue);
}
}
fclose(fp);
if (!cfg->ruleparam_db_fn)
cfg->ruleparam_db_fn = strdup( RULEPARAM_DB_FILE );
// If there were any errors, bail out
//
if ( (cfg->hash_modulus <= 0) ||
(cfg->n_one_cred_max_bank <= 0) ||
(cfg->n_two_cred_max_bank <= 0) ||
(cfg->n_spillover_max_bank <= 0) ||
(cfg->n_one_cred_bank_size <= 0) ||
(cfg->n_two_cred_bank_size <= 0) ||
(cfg->n_spillover_bank_size <= 0) ||
(cfg->n_one_cred_bank <= 0) ||
(cfg->n_two_cred_bank <= 0) ||
(cfg->n_spillover_bank <= 0) ||
(cfg->high_watermark_threshold <= 0.0) ||
(cfg->high_watermark_threshold >= 1.0) ||
(cfg->low_watermark_threshold <= 0.0) ||
(cfg->low_watermark_threshold >= cfg->high_watermark_threshold) ||
(!cfg->one_cred_db_base_fn) ||
(!cfg->two_cred_db_base_fn) ||
(!cfg->spillover_db_base_fn) ||
(!cfg->db_fn_suffix) ||
(!cfg->ruleparam_db_fn)
)
{
if (cfg->one_cred_db_base_fn) free(cfg->one_cred_db_base_fn);
if (cfg->two_cred_db_base_fn) free(cfg->two_cred_db_base_fn);
if (cfg->spillover_db_base_fn) free(cfg->spillover_db_base_fn);
if (cfg->db_fn_suffix) free(cfg->db_fn_suffix);
if (cfg->ruleparam_db_fn) free(cfg->ruleparam_db_fn);
return -1;
}
return 0;
}
// Dead simple config file parsing
//
int init_context_from_config( passdb_slim_context *ctx, char *config_fn )
{
int i, r;
// Don't copy new values over until we're sure config file read
// was successful. Store in local variables and copy over
// afterwards.
//
passdb_slim_config cfg;
r = read_config(&cfg, config_fn);
if (r<0)
return r;
ctx->n_one_cred_bank = cfg.n_one_cred_bank;
ctx->n_two_cred_bank = cfg.n_two_cred_bank;
ctx->n_spillover_bank = cfg.n_spillover_bank;
ctx->n_one_cred_max_bank = cfg.n_one_cred_max_bank;
ctx->n_two_cred_max_bank = cfg.n_two_cred_max_bank;
ctx->n_spillover_max_bank = cfg.n_spillover_max_bank;
ctx->n_one_cred_bank_size = cfg.n_one_cred_bank_size;
ctx->n_two_cred_bank_size = cfg.n_two_cred_bank_size;
ctx->n_spillover_bank_size = cfg.n_spillover_bank_size;
ctx->hash_modulus = cfg.hash_modulus;
// Get rid of stale filenames
//
if (ctx->one_cred_db_bank_fn)
{
for (i=0; in_one_cred_max_bank; i++)
if (ctx->one_cred_db_bank_fn[i])
free(ctx->one_cred_db_bank_fn[i]);
free(ctx->one_cred_db_bank_fn);
}
if (ctx->two_cred_db_bank_fn)
{
for (i=0; in_two_cred_max_bank; i++)
if (ctx->two_cred_db_bank_fn[i])
free(ctx->two_cred_db_bank_fn[i]);
free(ctx->two_cred_db_bank_fn);
}
if (ctx->spillover_db_bank_fn)
{
for (i=0; in_spillover_max_bank; i++)
if (ctx->spillover_db_bank_fn[i])
free(ctx->spillover_db_bank_fn[i]);
free(ctx->spillover_db_bank_fn);
}
if (ctx->one_cred_db_base_fn) free(ctx->one_cred_db_base_fn);
if (ctx->two_cred_db_base_fn) free(ctx->two_cred_db_base_fn);
if (ctx->spillover_db_base_fn) free(ctx->spillover_db_base_fn);
if (ctx->db_fn_suffix) free(ctx->db_fn_suffix);
if (ctx->ruleparam_db_fn) free(ctx->ruleparam_db_fn);
if (ctx->logical_card_id_hash) free(ctx->logical_card_id_hash);
if (ctx->rider_mag_hash) free(ctx->rider_mag_hash);
if (ctx->rider_rf_hash) free(ctx->rider_rf_hash);
ctx->one_cred_db_base_fn = cfg.one_cred_db_base_fn;
ctx->two_cred_db_base_fn = cfg.two_cred_db_base_fn;
ctx->spillover_db_base_fn = cfg.spillover_db_base_fn;
ctx->db_fn_suffix = cfg.db_fn_suffix;
ctx->ruleparam_db_fn = cfg.ruleparam_db_fn;
ctx->high_watermark_threshold = cfg.high_watermark_threshold;
ctx->low_watermark_threshold = cfg.low_watermark_threshold;
//---------------------------------------
// ONE CREDENTIAL bank
// - filenames
// - file descriptors
// - bank (memory)
//
// allocate all filenames, even if we don't create the actual DB files
//
ctx->one_cred_db_bank_fn = (char **)malloc(sizeof(char *) * (ctx->n_one_cred_max_bank));
CHECK_ALLOC_FAIL( (ctx->one_cred_db_bank_fn) );
for (i=0; in_one_cred_max_bank; i++)
{
ctx->one_cred_db_bank_fn[i] = (char *)malloc(sizeof(char)*FN_SZ);
CHECK_ALLOC_FAIL( (ctx->one_cred_db_bank_fn[i]) );
snprintf(ctx->one_cred_db_bank_fn[i], FN_SZ, "%s%i%s", ctx->one_cred_db_base_fn, i, ctx->db_fn_suffix );
}
ctx->passes_one_cred_bank_fd = (int *)malloc(sizeof(int) * ctx->n_one_cred_max_bank );
CHECK_ALLOC_FAIL( (ctx->passes_one_cred_bank_fd) );
for (i=0; in_one_cred_max_bank; i++)
ctx->passes_one_cred_bank_fd[i] = -1;
ctx->rider_one_cred_bank = (void **)malloc(sizeof(void *) * ctx->n_one_cred_max_bank );
CHECK_ALLOC_FAIL( (ctx->rider_one_cred_bank) );
for (i=0; in_one_cred_max_bank; i++)
ctx->rider_one_cred_bank[i] = NULL;
//---------------------------------------
// TWO CREDENTIAL bank
// - filenames
// - file descriptors
// - bank (memory)
//
// allocate all filenames, even if we don't create the actual DB files
//
ctx->two_cred_db_bank_fn = (char **)malloc(sizeof(char *) * (ctx->n_two_cred_max_bank));
CHECK_ALLOC_FAIL( (ctx->two_cred_db_bank_fn) );
for (i=0; in_two_cred_max_bank; i++)
{
ctx->two_cred_db_bank_fn[i] = (char *)malloc(sizeof(char)*FN_SZ);
CHECK_ALLOC_FAIL( (ctx->two_cred_db_bank_fn[i]) );
snprintf(ctx->two_cred_db_bank_fn[i], FN_SZ, "%s%i%s", ctx->two_cred_db_base_fn, i, ctx->db_fn_suffix );
}
ctx->passes_two_cred_bank_fd = (int *)malloc(sizeof(int) * ctx->n_two_cred_max_bank );
CHECK_ALLOC_FAIL( (ctx->passes_two_cred_bank_fd) );
for (i=0; in_two_cred_max_bank; i++)
ctx->passes_two_cred_bank_fd[i] = -1;
ctx->rider_two_cred_bank = (void **)malloc(sizeof(void *) * ctx->n_two_cred_max_bank );
CHECK_ALLOC_FAIL( (ctx->rider_two_cred_bank) );
for (i=0; in_two_cred_max_bank; i++)
ctx->rider_two_cred_bank[i] = NULL;
//---------------------------------------
// SPILLOVER
// - filenames
// - file descriptors
// - bank (memory)
//
// allocate all filenames, even if we don't create the actual DB files
//
ctx->spillover_db_bank_fn = (char **)malloc(sizeof(char *) * (ctx->n_spillover_max_bank));
CHECK_ALLOC_FAIL( (ctx->spillover_db_bank_fn) );
for (i=0; in_spillover_max_bank; i++)
{
ctx->spillover_db_bank_fn[i] = (char *)malloc(sizeof(char)*FN_SZ);
CHECK_ALLOC_FAIL( (ctx->spillover_db_bank_fn[i]) );
snprintf(ctx->spillover_db_bank_fn[i], FN_SZ, "%s%i%s", ctx->spillover_db_base_fn, i, ctx->db_fn_suffix );
}
ctx->passes_spillover_bank_fd = (int *)malloc(sizeof(int) * ctx->n_spillover_max_bank );
CHECK_ALLOC_FAIL( (ctx->passes_spillover_bank_fd) );
for (i=0; in_spillover_max_bank; i++)
ctx->passes_spillover_bank_fd[i] = -1;
ctx->rider_spillover_bank = (void **)malloc(sizeof(void *) * ctx->n_spillover_max_bank );
CHECK_ALLOC_FAIL( (ctx->rider_spillover_bank) );
for (i=0; in_spillover_max_bank; i++)
ctx->rider_spillover_bank[i] = NULL;
ctx->logical_card_id_hash = (rider_node **)malloc(sizeof(rider_node *) * ctx->hash_modulus );
CHECK_ALLOC_FAIL( (ctx->logical_card_id_hash) );
ctx->rider_mag_hash = (rider_node **)malloc(sizeof(rider_node *) * ctx->hash_modulus );
CHECK_ALLOC_FAIL( (ctx->rider_mag_hash) );
ctx->rider_rf_hash = (rider_node **)malloc(sizeof(rider_node *) * ctx->hash_modulus );
CHECK_ALLOC_FAIL( (ctx->rider_rf_hash) );
for (i=0; ihash_modulus; i++)
{
ctx->logical_card_id_hash[i] = NULL;
ctx->rider_mag_hash[i] = NULL;
ctx->rider_rf_hash[i] = NULL;
}
return 0;
}