From e8a376a87f4c0f310af032cebd554d342f058066 Mon Sep 17 00:00:00 2001 From: Viktor Krikun Date: Fri, 25 Nov 2011 19:13:16 +0000 Subject: [PATCH] First draft implementation of random-access cache (refs #25) --- include/zrtp_iface_cache.h | 10 +- include/zrtp_types.h | 1 + projects/gnu/build/test/Makefile.am | 46 ++++--- src/zrtp_iface_cache.c | 192 +++++++++++++++++++++++----- test/cache_test.c | 127 ++++++++++++++++++ 5 files changed, 326 insertions(+), 50 deletions(-) create mode 100644 test/cache_test.c diff --git a/include/zrtp_iface_cache.h b/include/zrtp_iface_cache.h index 9a60b83496..81d8fbd359 100644 --- a/include/zrtp_iface_cache.h +++ b/include/zrtp_iface_cache.h @@ -34,8 +34,8 @@ extern "C" */ typedef uint8_t zrtp_cache_id_t[24]; -#define ZRTP_MITMCACHE_ELEM_LENGTH (sizeof(zrtp_cache_id_t) + sizeof(zrtp_string64_t)) -#define ZRTP_CACHE_ELEM_LENGTH (sizeof(zrtp_cache_elem_t) - sizeof(mlist_t)) +#define ZRTP_MITMCACHE_ELEM_LENGTH ( sizeof(zrtp_cache_id_t) + sizeof(zrtp_string64_t) ) +#define ZRTP_CACHE_ELEM_LENGTH ( sizeof(zrtp_cache_elem_t) - sizeof(mlist_t) - (sizeof(uint32_t)*2) ) #define ZFONE_CACHE_NAME_LENGTH 256 /** @@ -51,10 +51,12 @@ typedef struct zrtp_cache_elem uint32_t verified; /** Verified flag for the cache value */ uint32_t lastused_at; /** Last usage time-stamp in seconds */ uint32_t ttl; /** Cache TTL since lastused_at in seconds */ - uint32_t secure_since; /** Secure since date in seconds. Utility field. Doen't required by libzrtp. */ + uint32_t secure_since; /** Secure since date in seconds. Utility field. Don't required by libzrtp. */ char name[ZFONE_CACHE_NAME_LENGTH]; /** name of the user associated with this cache entry */ uint32_t name_length; /** cache name lengths */ - uint32_t presh_counter; /** number of Preshared streams made since last DH echange */ + uint32_t presh_counter; /** number of Preshared streams made since last DH exchange */ + uint32_t _index; /** cache element index in the cache file */ + uint32_t _is_dirty; /** dirty flag means the entry has unsaved changes */ mlist_t _mlist; } zrtp_cache_elem_t; diff --git a/include/zrtp_types.h b/include/zrtp_types.h index fa7b0f1034..a38d118591 100644 --- a/include/zrtp_types.h +++ b/include/zrtp_types.h @@ -359,6 +359,7 @@ struct zrtp_global_t /** RNG unit initialization flag. */ uint8_t rand_initialized; + /** Full path to ZRTP cache file. */ zrtp_string256_t def_cache_path; /** This object is used to protect the shared RNG hash zrtp#rand_ctx */ diff --git a/projects/gnu/build/test/Makefile.am b/projects/gnu/build/test/Makefile.am index 5c1f3886a0..558b2b9e5a 100644 --- a/projects/gnu/build/test/Makefile.am +++ b/projects/gnu/build/test/Makefile.am @@ -11,33 +11,47 @@ TOP_SRCDIR=$(top_srcdir)/../.. INCLUDES = -I$(TOP_SRCDIR)/include \ -I$(TOP_SRCDIR)/include/enterprise \ -I$(TOP_SRCDIR)/. \ + -I$(TOP_SRCDIR)/test \ + -I$(TOP_SRCDIR)/test/cmockery \ -I$(TOP_SRCDIR)/third_party/bgaes \ -I$(TOP_SRCDIR)/third_party/bnlib -check_PROGRAMS = libzrtp_test +#check_PROGRAMS = cache_test libzrtp_test +check_PROGRAMS = cache_test + +### ZRTP Cache testing + +cache_test_SOURCES = $(TOP_SRCDIR)/test/cmockery/cmockery.c \ + $(TOP_SRCDIR)/test/cache_test.c +cache_test_LDADD = ../libzrtp.a $(TOP_SRCDIR)/third_party/bnlib/libbn.a -lpthread + + +### ZRTP high-level test-case libzrtp_test_SOURCES = $(TOP_SRCDIR)/test/pc/zrtp_test_core.c \ $(TOP_SRCDIR)/test/pc/zrtp_test_crypto.c \ $(TOP_SRCDIR)/test/pc/zrtp_test_queue.c \ $(TOP_SRCDIR)/test/pc/zrtp_test_ui.c -libzrtp_test_LDADD = ../libzrtp.a \ - $(TOP_SRCDIR)/third_party/bnlib/libbn.a -lpthread +libzrtp_test_LDADD = ../libzrtp.a $(TOP_SRCDIR)/third_party/bnlib/libbn.a -lpthread SUBDIRS = . -check: - @echo "" - @echo "*========================================================================*" - @echo "* starting libZRTP tests *" - @echo "*========================================================================*" - @echo "" - @./libzrtp_test +check: +# @ ./cache_test - @echo "" - @echo "*========================================================================*" - @echo "* In case you have a test FAILED send the generated log file *" - @echo "* with your comment to . *" - @echo "*========================================================================*" - @echo "" +# check: +# @echo "" +# @echo "*========================================================================*" +# @echo "* starting libZRTP tests *" +# @echo "*========================================================================*" +# @echo "" +# @./libzrtp_test +# +# @echo "" +# @echo "*========================================================================*" +# @echo "* In case you have a test FAILED send the generated log file *" +# @echo "* with your comment to . *" +# @echo "*========================================================================*" +# @echo "" diff --git a/src/zrtp_iface_cache.c b/src/zrtp_iface_cache.c index 7f7c10484c..e28bb7bee7 100644 --- a/src/zrtp_iface_cache.c +++ b/src/zrtp_iface_cache.c @@ -18,7 +18,9 @@ #if (ZRTP_PLATFORM != ZP_WIN32_KERNEL) static mlist_t cache_head; +static uint32_t g_cache_elems_counter = 0; static mlist_t mitmcache_head; +static uint32_t g_mitmcache_elems_counter = 0; static uint8_t inited = 0; static zrtp_global_t* zrtp; @@ -95,6 +97,7 @@ void zrtp_def_cache_down() zrtp_mutex_destroy(def_cache_protector); inited = 0; + zrtp = NULL; } } @@ -158,7 +161,7 @@ static zrtp_status_t cache_put( const zrtp_stringn_t* one_ZID, new_elem = get_elem(id, is_mitm); if (!new_elem) { - /* If cache doesn't exist - create ne one */ + /* If cache doesn't exist - create new one */ if (!( new_elem = (zrtp_cache_elem_t*) zrtp_sys_alloc(sizeof(zrtp_cache_elem_t)) )) { break; } @@ -171,9 +174,15 @@ static zrtp_status_t cache_put( const zrtp_stringn_t* one_ZID, mlist_add_tail(is_mitm ? &mitmcache_head : &cache_head, &new_elem->_mlist); zrtp_memcpy(new_elem->id, id, sizeof(zrtp_cache_id_t)); + + if (is_mitm) { + new_elem->_index = g_mitmcache_elems_counter++; + } else { + new_elem->_index = g_cache_elems_counter++; + } } - /* Save current cache value as previous one and new as a current */ + /* Save current cache value as previous one and new as a current */ if (!is_mitm) { if (new_elem->curr_cache.length > 0) { zrtp_zstrcpy(ZSTR_GV(new_elem->prev_cache), ZSTR_GV(new_elem->curr_cache)); @@ -185,6 +194,8 @@ static zrtp_status_t cache_put( const zrtp_stringn_t* one_ZID, if (!is_mitm) { new_elem->ttl = rss->ttl; } + + new_elem->_is_dirty = 1; } while (0); zrtp_mutex_unlock(def_cache_protector); @@ -193,7 +204,7 @@ static zrtp_status_t cache_put( const zrtp_stringn_t* one_ZID, zrtp_status_t zrtp_def_cache_put( const zrtp_stringn_t* one_ZID, const zrtp_stringn_t* another_ZID, - zrtp_shared_secret_t *rss) { + zrtp_shared_secret_t *rss) { return cache_put(one_ZID, another_ZID, rss, 0); } @@ -270,6 +281,8 @@ zrtp_status_t zrtp_def_cache_set_presh_counter( const zrtp_stringn_t* one_zid, if (new_elem) { ZRTP_LOG(3,(_ZTU_,"\tTEST! Update counter to %u.\n", counter)); new_elem->presh_counter = counter; + + new_elem->_is_dirty = 1; } zrtp_mutex_unlock(def_cache_protector); @@ -394,6 +407,7 @@ zrtp_status_t zrtp_cache_user_init() uint32_t i = 0; unsigned is_unsupported = 0; + ZRTP_LOG(3,(_ZTU_,"\tLoad ZRTP cache from <%s>...\n", zrtp->def_cache_path.buffer)); /* Try to open existing file. If ther is no cache file - start with empty cache */ #if (ZRTP_PLATFORM == ZP_WIN32) @@ -402,6 +416,7 @@ zrtp_status_t zrtp_cache_user_init() } #else if (0 == (cache_file = fopen(zrtp->def_cache_path.buffer, "rb"))) { + ZRTP_LOG(3,(_ZTU_,"\tCan't open file for reading.\n")); return zrtp_status_ok; } #endif @@ -413,43 +428,50 @@ zrtp_status_t zrtp_cache_user_init() */ do { char version_buff[256]; + memset(version_buff, 0, sizeof(version_buff)); if (fread(version_buff, strlen(ZRTP_DEF_CACHE_VERSION_STR)+strlen(ZRTP_DEF_CACHE_VERSION_VAL), 1, cache_file) <= 0) { - ZRTP_LOG(3,(_ZTU_,"Cache file is too small.\n")); + ZRTP_LOG(3,(_ZTU_,"\tCache Error: Cache file is too small.\n")); is_unsupported = 1; break; } if (0 != zrtp_memcmp(version_buff, ZRTP_DEF_CACHE_VERSION_STR, strlen(ZRTP_DEF_CACHE_VERSION_STR))) { - ZRTP_LOG(3,(_ZTU_,"Can't find ZRTP Version tag in the cache file.\n")); + ZRTP_LOG(3,(_ZTU_,"\tCache Error: Can't find ZRTP Version tag in the cache file.\n")); is_unsupported = 1; break; } + ZRTP_LOG(3,(_ZTU_,"\tZRTP cache file has version=%s\n", version_buff+strlen(ZRTP_DEF_CACHE_VERSION_STR))); + if (0 != zrtp_memcmp(version_buff+strlen(ZRTP_DEF_CACHE_VERSION_STR), ZRTP_DEF_CACHE_VERSION_VAL, strlen(ZRTP_DEF_CACHE_VERSION_VAL))) { - ZRTP_LOG(3,(_ZTU_,"Usupported ZRTP cache version.\n")); + ZRTP_LOG(3,(_ZTU_,"\tCache Error: Unsupported ZRTP cache version.\n")); is_unsupported = 1; break; - } + } } while (0); if (is_unsupported) { - ZRTP_LOG(3,(_ZTU_,"Unsupported version of ZRTP cache file detected - white-out the cache.\n")); + ZRTP_LOG(3,(_ZTU_,"\tCache Error: Unsupported version of ZRTP cache file detected - white-out the cache.\n")); fclose(cache_file); return zrtp_status_ok; } + g_mitmcache_elems_counter = 0; /* - * Load MitM caches: first 32 bits is a mitm secrets counter. Read it and then + * Load MitM caches: first 32 bits is a MiTM secrets counter. Read it and then * upload appropriate number of MitM secrets. */ do { + cache_elems_count = 0; if (fread(&mitmcache_elems_count, 4, 1, cache_file) <= 0) { ZRTP_INT_CACHE_BREAK(s, zrtp_status_read_fail); } + mitmcache_elems_count = zrtp_ntoh32(mitmcache_elems_count); + + ZRTP_LOG(3,(_ZTU_,"\tZRTP cache file contains %u MiTM secrets.\n", mitmcache_elems_count)); - mitmcache_elems_count = zrtp_ntoh32(mitmcache_elems_count); for (i=0; i_index = g_mitmcache_elems_counter++; + new_elem->_is_dirty = 0; + mlist_add_tail(&mitmcache_head, &new_elem->_mlist); } @@ -474,18 +502,25 @@ zrtp_status_t zrtp_cache_user_init() zrtp_def_cache_down(); return s; } + + ZRTP_LOG(3,(_ZTU_,"\tAll %u MiTM Cache entries have been uploaded.\n", g_mitmcache_elems_counter)); /* * Load regular caches: first 32 bits is a secrets counter. Read it and then * upload appropriate number of regular secrets. */ + cache_elems_count = 0; if (fread(&cache_elems_count, 4, 1, cache_file) <= 0) { fclose(cache_file); zrtp_def_cache_down(); return zrtp_status_read_fail; - } - + } cache_elems_count = zrtp_ntoh32(cache_elems_count); + + g_cache_elems_counter = 0; + + ZRTP_LOG(3,(_ZTU_,"\tZRTP cache file contains %u RS secrets.\n", cache_elems_count)); + for (i=0; i_index = g_cache_elems_counter++; + new_elem->_is_dirty = 0; + mlist_add_tail(&cache_head, &new_elem->_mlist); } if (i != cache_elems_count) { @@ -510,6 +550,8 @@ zrtp_status_t zrtp_cache_user_init() return zrtp_status_fail; } + ZRTP_LOG(3,(_ZTU_,"\tAll of %u RS Cache entries have been uploaded.\n", g_cache_elems_counter)); + return s; } @@ -525,15 +567,65 @@ zrtp_status_t zrtp_cache_user_init() return s;\ }; +static zrtp_status_t flush_elem_(zrtp_cache_elem_t *elem, FILE *cache_file, unsigned is_mitm) { + zrtp_cache_elem_t tmp_elem; + uint32_t pos = 0; + + /* + * Let's calculate cache element position in the file + */ + printf("flush_elem_(): calculate Element offset for %s..\n", is_mitm?"MiTM":"RS"); + + /* Skip the header */ + pos += strlen(ZRTP_DEF_CACHE_VERSION_STR)+strlen(ZRTP_DEF_CACHE_VERSION_VAL); + + pos += sizeof(uint32_t); /* Skip MiTM secretes count. */ + + printf("flush_elem_(): \t pos=%u (Header, MiTM Count).\n", pos); + + if (is_mitm) { + /* position within MiTM secrets block. */ + pos += (elem->_index * ZRTP_MITMCACHE_ELEM_LENGTH); + printf("flush_elem_(): \t pos=%u (Header, MiTM Count + %u MiTM Secrets).\n", pos, elem->_index); + } else { + /* Skip MiTM Secrets block */ + pos += (g_mitmcache_elems_counter * ZRTP_MITMCACHE_ELEM_LENGTH); + + pos += sizeof(uint32_t); /* Skip RS elements count. */ + + pos += (elem->_index * ZRTP_CACHE_ELEM_LENGTH); /* Skip previous RS elements */ + + printf("flush_elem_(): \t pos=%u (Header, MiTM Count + ALL %u Secrets, RS counter and %u prev. RS).\n", pos, g_mitmcache_elems_counter, elem->_index); + } + + fseek(cache_file, pos, SEEK_SET); + + /* Prepare element for storing, convert all fields to the network byte-order. */ + cache_make_cross(elem, &tmp_elem, 0); + + printf("flush_elem_(): write to offset=%lu\n", ftell(cache_file)); + + /* Flush the element. */ + if (fwrite(&tmp_elem, (is_mitm ? ZRTP_MITMCACHE_ELEM_LENGTH : ZRTP_CACHE_ELEM_LENGTH), 1, cache_file) != 1) { + printf("flush_elem_(): ERROR!!! write failed!\n"); + return zrtp_status_write_fail; + } else { + elem->_is_dirty = 0; + + printf("flush_elem_(): OK! %lu bytes were written\n", (is_mitm ? ZRTP_MITMCACHE_ELEM_LENGTH : ZRTP_CACHE_ELEM_LENGTH)); + return zrtp_status_ok; + } +} + zrtp_status_t zrtp_cache_user_down() { FILE* cache_file = 0; - zrtp_cache_elem_t tmp_elem; mlist_t *node = 0; uint32_t count = 0; uint32_t pos = 0; - ZRTP_LOG(3,(_ZTU_,"\tStoring ZRTP cache to the file...\n")); + ZRTP_LOG(3,(_ZTU_,"\tStoring ZRTP cache to <%s>...\n", zrtp->def_cache_path.buffer)); + /* Open/create file for writing */ #if (ZRTP_PLATFORM == ZP_WIN32) if (0 != fopen_s(&cache_file, zrtp->def_cache_path.buffer, "wb+")) { @@ -550,53 +642,81 @@ zrtp_status_t zrtp_cache_user_down() /* Store version string first. Format: &ZRTP_DEF_CACHE_VERSION_STR&ZRTP_DEF_CACHE_VERSION_VAL */ if (1 != fwrite(ZRTP_DEF_CACHE_VERSION_STR, strlen(ZRTP_DEF_CACHE_VERSION_STR), 1, cache_file)) { + ZRTP_LOG(2,(_ZTU_,"\tERROR! unable to write header to the cache file\n")); ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); } if (1 != fwrite(ZRTP_DEF_CACHE_VERSION_VAL, strlen(ZRTP_DEF_CACHE_VERSION_VAL), 1, cache_file)) { + ZRTP_LOG(2,(_ZTU_,"\tERROR! unable to write header to the cache file\n")); ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); } - /* Store PBX secrets first. Format: , */ + /* + * Store PBX secrets first. Format: , + * + * NOTE!!! It's IMPORTANT to store PBX secrets before the Regular secrets!!! + */ pos = ftell(cache_file); + count = 0; fwrite(&count, sizeof(count), 1, cache_file); + mlist_for_each(node, &mitmcache_head) { zrtp_cache_elem_t* elem = mlist_get_struct(zrtp_cache_elem_t, _mlist, node); - cache_make_cross(elem, &tmp_elem, 0); - if (fwrite(&tmp_elem, ZRTP_MITMCACHE_ELEM_LENGTH, 1, cache_file) != 1) { - ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); + /* Store dirty values only. */ + if (elem->_is_dirty) { + printf("zrtp_cache_user_down: Store MiTM elem index=%u, not modified.\n", elem->_index); + if (zrtp_status_ok != flush_elem_(elem, cache_file, 1)) { + ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); + } + } else { + printf("zrtp_cache_user_down: Skip MiTM elem index=%u, not modified.\n", elem->_index); } - count++; } fseek(cache_file, pos, SEEK_SET); - count = zrtp_hton32(count); + + count = zrtp_hton32(g_mitmcache_elems_counter); if (fwrite(&count, sizeof(count), 1, cache_file) != 1) { ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); } - fseek(cache_file, 0L, SEEK_END); - ZRTP_LOG(3,(_ZTU_,"\t%u MiTM cache entries have been stored sucessfully.\n",zrtp_ntoh32(count))); + ZRTP_LOG(3,(_ZTU_,"\t%u MiTM cache entries have been stored successfully.\n",zrtp_ntoh32(count))); + + /* + * Store regular secrets. Format: , + */ + + /* Seek to the beginning of the Regular secrets block */ + pos = strlen(ZRTP_DEF_CACHE_VERSION_STR)+strlen(ZRTP_DEF_CACHE_VERSION_VAL); + pos += sizeof(uint32_t); /* Skip MiTM secrets count. */ + pos += (g_mitmcache_elems_counter * ZRTP_MITMCACHE_ELEM_LENGTH); /* Skip MiTM Secrets block */ + + fseek(cache_file, pos, SEEK_SET); - /* Store reqular secrets. Format: , */ - pos = ftell(cache_file); count = 0; fwrite(&count, sizeof(count), 1, cache_file); + mlist_for_each(node, &cache_head) { zrtp_cache_elem_t* elem = mlist_get_struct(zrtp_cache_elem_t, _mlist, node); - cache_make_cross(elem, &tmp_elem, 0); - if (fwrite(&tmp_elem, ZRTP_CACHE_ELEM_LENGTH, 1, cache_file) != 1) { - ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); + + /* Store dirty values only. */ + if (elem->_is_dirty) { + printf("zrtp_cache_user_down: Store RS elem index=%u, not modified.\n", elem->_index); + if (zrtp_status_ok != flush_elem_(elem, cache_file, 0)) { + ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); + } + } else { + printf("zrtp_cache_user_down: Skip RS elem index=%u, not modified.\n", elem->_index); } - count++; } fseek(cache_file, pos, SEEK_SET); - count = zrtp_hton32(count); + + count = zrtp_hton32(g_cache_elems_counter); if (fwrite(&count, sizeof(count), 1, cache_file) != 1) { ZRTP_DOWN_CACHE_RETURN(zrtp_status_write_fail, cache_file); } - ZRTP_LOG(3,(_ZTU_,"\t%u regular cache entries have been stored sucessfully.\n", zrtp_ntoh32(count))); + ZRTP_LOG(3,(_ZTU_,"\t%u regular cache entries have been stored successfully.\n", zrtp_ntoh32(count))); ZRTP_DOWN_CACHE_RETURN(zrtp_status_ok, cache_file); } @@ -633,6 +753,8 @@ static zrtp_status_t put_name( const zrtp_stringn_t* one_ZID, new_elem->name_length = ZRTP_MIN(name->length, ZFONE_CACHE_NAME_LENGTH-1); zrtp_memset(new_elem->name, 0, sizeof(new_elem->name)); zrtp_memcpy(new_elem->name, name->buffer, new_elem->name_length); + + new_elem->_is_dirty = 1; } while (0); zrtp_mutex_unlock(def_cache_protector); @@ -720,6 +842,8 @@ zrtp_status_t zrtp_def_cache_reset_since( const zrtp_stringn_t* one_zid, new_elem = get_elem(id, 0); if (new_elem) { new_elem->secure_since = (uint32_t)(zrtp_time_now()/1000); + + new_elem->_is_dirty = 1; } zrtp_mutex_unlock(def_cache_protector); @@ -743,6 +867,14 @@ void zrtp_def_cache_foreach( zrtp_global_t *global, result = callback(elem, is_mitm, data, &delete); if (delete) { mlist_del(&elem->_mlist); + + if (is_mitm) + g_mitmcache_elems_counter--; + else + g_cache_elems_counter--; + + // TODO: rearrange INDEXES here! + } if (!result) { break; diff --git a/test/cache_test.c b/test/cache_test.c new file mode 100644 index 0000000000..7a4fbef707 --- /dev/null +++ b/test/cache_test.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include + #include + +#include "zrtp.h" +#include "cmockery/cmockery.h" + +#define TEST_CACHE_PATH "./zrtp_cache_test.dat" + +static zrtp_global_t g_zrtp_cfg; + +void cache_setup() { + remove(TEST_CACHE_PATH); + + ZSTR_SET_EMPTY(g_zrtp_cfg.def_cache_path); + /* Configure and Initialize ZRTP cache */ + zrtp_zstrcpyc(ZSTR_GV(g_zrtp_cfg.def_cache_path), TEST_CACHE_PATH); +} + +void cache_teardown() { + zrtp_def_cache_down(); +} + +static void init_rs_secret_(zrtp_shared_secret_t *sec) { + ZSTR_SET_EMPTY(sec->value); + + sec->_cachedflag = 0; + sec->ttl = 0; + sec->lastused_at = 0; +} + + +/* + * Simply init ZRTP cache with empty or non-existing filer and close it. + * The app should not crash and trigger no errors. +*/ +void cache_init_store_empty_test() { + zrtp_status_t status; + + /* It should NOT crash and return OK. */ + status = zrtp_def_cache_init(&g_zrtp_cfg); + assert_int_equal(status, zrtp_status_ok); + + zrtp_def_cache_down(); +} + +/* + * Add few entries to the empty cache, flush it and then load again. Check if + * all the entries were restored successfully. + */ +void cache_add2empty_test() { + zrtp_status_t status; + + int intres; + + zrtp_string16_t zid_my = ZSTR_INIT_WITH_CONST_CSTRING("000000000_01"); + zrtp_string16_t zid_a = ZSTR_INIT_WITH_CONST_CSTRING("000000000_02"); + zrtp_string16_t zid_b = ZSTR_INIT_WITH_CONST_CSTRING("000000000_03"); + zrtp_string16_t zid_c = ZSTR_INIT_WITH_CONST_CSTRING("000000000_04"); + zrtp_string16_t zid_mitm1 = ZSTR_INIT_WITH_CONST_CSTRING("000000000_04"); + + zrtp_shared_secret_t rs_my4a, rs_my4b, rs_my4c, rs_my4mitm1; + zrtp_shared_secret_t rs_my4a_r, rs_my4b_r, rs_my4c_r, rs_my4mitm1_r; + + init_rs_secret_(&rs_my4a); init_rs_secret_(&rs_my4b); + init_rs_secret_(&rs_my4c); init_rs_secret_(&rs_my4mitm1); + + init_rs_secret_(&rs_my4a_r); init_rs_secret_(&rs_my4b_r); + init_rs_secret_(&rs_my4c_r); init_rs_secret_(&rs_my4mitm1_r); + + printf("Open empty cache file for.\n"); + status = zrtp_def_cache_init(&g_zrtp_cfg); + assert_int_equal(status, zrtp_status_ok); + + /* Test if cache-init does bot corrupt config. */ + assert_false(strncmp(g_zrtp_cfg.def_cache_path.buffer, TEST_CACHE_PATH, strlen(TEST_CACHE_PATH))); + + /* Add few values into it */ + printf("Add few test entries.\n"); + + status = zrtp_def_cache_put(ZSTR_GV(zid_my), ZSTR_GV(zid_a), &rs_my4a); + assert_int_equal(status, zrtp_status_ok); + + status = zrtp_def_cache_put(ZSTR_GV(zid_my), ZSTR_GV(zid_b), &rs_my4b); + assert_int_equal(status, zrtp_status_ok); + + status = zrtp_def_cache_put_mitm(ZSTR_GV(zid_my), ZSTR_GV(zid_mitm1), &rs_my4mitm1); + assert_int_equal(status, zrtp_status_ok); + + status = zrtp_def_cache_put(ZSTR_GV(zid_my), ZSTR_GV(zid_c), &rs_my4c); + assert_int_equal(status, zrtp_status_ok); + + /* Close the cache, it should be flushed to the file. */ + printf("Close the cache.\n"); + + zrtp_def_cache_down(); + + /* Test if cache-close does bot corrupt config. */ + assert_false(strncmp(g_zrtp_cfg.def_cache_path.buffer, TEST_CACHE_PATH, strlen(TEST_CACHE_PATH))); + + /* Now, let's open the cache again and check if all the previously added values were restored successfully */ + printf("And open it again, it should contain all the stored values.\n"); + + status = zrtp_def_cache_init(&g_zrtp_cfg); + assert_int_equal(status, zrtp_status_ok); + + status = zrtp_def_cache_get(ZSTR_GV(zid_my), ZSTR_GV(zid_a), &rs_my4a_r, 0); + assert_int_equal(status, zrtp_status_ok); + + assert_false(zrtp_zstrcmp(ZSTR_GV(rs_my4a_r.value), ZSTR_GV(rs_my4a.value))); + + /* Test if cache-close does bot corrupt config. */ + assert_false(strncmp(g_zrtp_cfg.def_cache_path.buffer, TEST_CACHE_PATH, strlen(TEST_CACHE_PATH))); +} + + + +int main(void) { + const UnitTest tests[] = { + //unit_test_setup_teardown(cache_init_store_empty_test, cache_setup, cache_teardown), + unit_test_setup_teardown(cache_add2empty_test, cache_setup, cache_teardown), + }; + + return run_tests(tests); +}