int replaycache_add_and_test_internal( time_t present, replaycache_t *r, const void *data, int len, time_t *elapsed) { int rv = 0; char digest[DIGEST_LEN]; time_t *access_time; /* sanity check */ if (present <= 0 || !r || !data || len <= 0) { log_info(LD_BUG, "replaycache_add_and_test_internal() called with stupid" " parameters; please fix this."); goto done; } /* compute digest */ crypto_digest(digest, (const char *)data, len); /* check map */ access_time = digestmap_get(r->digests_seen, digest); /* seen before? */ if (access_time != NULL) { /* * If it's far enough in the past, no hit. If the horizon is zero, we * never expire. */ if (*access_time >= present - r->horizon || r->horizon == 0) { /* replay cache hit, return 1 */ rv = 1; /* If we want to output an elapsed time, do so */ if (elapsed) { if (present >= *access_time) { *elapsed = present - *access_time; } else { /* We shouldn't really be seeing hits from the future, but... */ *elapsed = 0; } } } /* * If it's ahead of the cached time, update */ if (*access_time < present) { *access_time = present; } } else { /* No, so no hit and update the digest map with the current time */ access_time = tor_malloc(sizeof(*access_time)); *access_time = present; digestmap_set(r->digests_seen, digest, access_time); } /* now scrub the cache if it's time */ replaycache_scrub_if_needed_internal(present, r); done: return rv; }
static void test_replaycache_scrub(void *arg) { replaycache_t *r = NULL; int result; (void)arg; r = replaycache_new(600, 300); tt_assert(r != NULL); /* Set up like in test_replaycache_hit() */ result = replaycache_add_and_test_internal(100, r, test_buffer, strlen(test_buffer), NULL); tt_int_op(result,OP_EQ, 0); result = replaycache_add_and_test_internal(200, r, test_buffer, strlen(test_buffer), NULL); tt_int_op(result,OP_EQ, 1); /* * Poke a few replaycache_scrub_if_needed_internal() error cases that * can't happen through replaycache_add_and_test_internal() */ /* Null cache */ replaycache_scrub_if_needed_internal(300, NULL); /* Assert we're still here */ tt_assert(1); /* Make sure we hit the aging-out case too */ replaycache_scrub_if_needed_internal(1500, r); /* Assert that we aged it */ tt_int_op(digestmap_size(r->digests_seen),OP_EQ, 0); done: if (r) replaycache_free(r); return; }
void replaycache_scrub_if_needed(replaycache_t *r) { replaycache_scrub_if_needed_internal(time(NULL), r); }