]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
First draft implementation of random-access cache
authorViktor Krikun <v.krikun@zfoneproject.com>
Fri, 25 Nov 2011 19:13:16 +0000 (19:13 +0000)
committerTravis Cross <tc@traviscross.com>
Sat, 31 Mar 2012 22:56:22 +0000 (22:56 +0000)
(refs #25)

include/zrtp_iface_cache.h
include/zrtp_types.h
projects/gnu/build/test/Makefile.am
src/zrtp_iface_cache.c
test/cache_test.c [new file with mode: 0644]

index 9a60b83496a5bf05fff59f34be7e542aeb399130..81d8fbd35926f84d3a3fe9bfffd35b4a49719fc0 100644 (file)
@@ -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;
        
index fa7b0f10345b186bf90ec52473a5dd38361ef51a..a38d1185918d2c9e2fdb70f3d47fa2143b79aa8e 100644 (file)
@@ -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 */
index 5c1f3886a00b6437279b31ae488f75b867a7e0fb..558b2b9e5af66db2891229914d05d92e44c0658a 100644 (file)
@@ -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
-
-       @echo ""
-       @echo "*========================================================================*"
-       @echo "* In case you have a test FAILED send the generated log file       *"
-       @echo "* with your comment to <zrtp_support@zfoneproject.com>.            *" 
-       @echo "*========================================================================*"
-       @echo ""
+check: 
+#      @ ./cache_test
+
+# 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 <zrtp_support@zfoneproject.com>.            *" 
+#      @echo "*========================================================================*"
+#      @echo ""
index 7f7c10484c5454b1f5cf32b865168aad33774429..e28bb7bee7aeb5a20c29a2dc1da727b56d82c5a8 100644 (file)
@@ -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<mitmcache_elems_count; i++)
                {
                        new_elem = (zrtp_cache_elem_t*) zrtp_sys_alloc(sizeof(zrtp_cache_elem_t));
@@ -458,11 +480,17 @@ zrtp_status_t zrtp_cache_user_init()
                        }
                        
                        if (fread(new_elem, ZRTP_MITMCACHE_ELEM_LENGTH, 1, cache_file) <= 0) {
+                               ZRTP_LOG(3,(_ZTU_,"\tERROR! MiTM cache element read fail (id=%u).\n", i));
+                               
                                zrtp_sys_free(new_elem);
                                ZRTP_INT_CACHE_BREAK(s, zrtp_status_read_fail);
                        }
 
                        cache_make_cross(NULL, new_elem, 1);
+                       
+                       new_elem->_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<cache_elems_count; i++)
        {
                new_elem = (zrtp_cache_elem_t*) zrtp_sys_alloc(sizeof(zrtp_cache_elem_t));
@@ -494,11 +529,16 @@ zrtp_status_t zrtp_cache_user_init()
                }
 
                if (fread(new_elem, ZRTP_CACHE_ELEM_LENGTH, 1, cache_file) <= 0) {
+                       ZRTP_LOG(3,(_ZTU_,"\tERROR! RS cache element read fail (id=%u).\n", i));
                        zrtp_sys_free(new_elem);
                        ZRTP_INT_CACHE_BREAK(s, zrtp_status_read_fail);                 
                }
 
                cache_make_cross(NULL, new_elem, 1);
+               
+               new_elem->_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: <secrets count>, <secrets' data> */
+    /*
+        * Store PBX secrets first. Format: <secrets count>, <secrets' data>
+        *
+        * 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: <secrets count>, <secrets' data>
+        */
+               
+       /* 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: <secrets count>, <secrets' data> */
-       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 (file)
index 0000000..7a4fbef
--- /dev/null
@@ -0,0 +1,127 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <string.h>
+ #include <stdio.h>
+
+#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);
+}