| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 |
- /*
- * 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 <https://www.gnu.org/licenses/>.
- *
- */
- #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; i<ctx->n_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; i<ctx->n_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; i<ctx->n_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; i<ctx->n_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; i<ctx->n_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; i<ctx->n_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; i<ctx->n_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; i<ctx->n_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; i<ctx->n_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; i<ctx->n_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; i<ctx->n_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; i<ctx->n_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; i<ctx->hash_modulus; i++)
- {
- ctx->logical_card_id_hash[i] = NULL;
- ctx->rider_mag_hash[i] = NULL;
- ctx->rider_rf_hash[i] = NULL;
- }
- return 0;
- }
|