]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Add high-level test engine
authorViktor Krykun <viktor@krykun.com>
Wed, 13 Jun 2012 12:23:30 +0000 (15:23 +0300)
committerTravis Cross <tc@traviscross.com>
Mon, 11 Feb 2013 16:41:46 +0000 (16:41 +0000)
Remove some old tests and implement a few test-cases to emulate zrtp
enrollment and sasrelay logic

Modified-by: Travis Cross <tc@traviscross.com>
Signed-off-by: Travis Cross <tc@traviscross.com>
12 files changed:
libs/libzrtp/build/test/Makefile.am
libs/libzrtp/test/enroll_test_helpers.c [new file with mode: 0644]
libs/libzrtp/test/enrollment_test.c [new file with mode: 0644]
libs/libzrtp/test/go_secure_test.c [new file with mode: 0644]
libs/libzrtp/test/pc/zrtp_test_core.c [deleted file]
libs/libzrtp/test/pc/zrtp_test_core.h [deleted file]
libs/libzrtp/test/pc/zrtp_test_ui.c [deleted file]
libs/libzrtp/test/queue.c [moved from libs/libzrtp/test/pc/zrtp_test_queue.c with 85% similarity]
libs/libzrtp/test/queue.h [moved from libs/libzrtp/test/pc/zrtp_test_queue.h with 96% similarity]
libs/libzrtp/test/sasrelay_test.c [new file with mode: 0644]
libs/libzrtp/test/test_engine.c [new file with mode: 0644]
libs/libzrtp/test/test_engine.h [new file with mode: 0644]

index b8f9a9abb9d7663f60c50ec911b6ad9b159900a1..4a9321c69ff7da1e869b69bd7f2416541eba92dd 100644 (file)
@@ -17,7 +17,6 @@ INCLUDES =    -I$(TOP_SRCDIR)/include \
                        -I$(TOP_SRCDIR)/third_party/bnlib
 
 
-#check_PROGRAMS = cache_test libzrtp_test
 check_PROGRAMS = cache_test
 
 ### ZRTP Cache testing
@@ -27,15 +26,6 @@ cache_test_SOURCES = $(TOP_SRCDIR)/test/cmockery/cmockery.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
-
 SUBDIRS = .
 
 check: 
diff --git a/libs/libzrtp/test/enroll_test_helpers.c b/libs/libzrtp/test/enroll_test_helpers.c
new file mode 100644 (file)
index 0000000..ef0973b
--- /dev/null
@@ -0,0 +1,81 @@
+
+static zrtp_test_id_t g_alice, g_bob, g_pbx;
+static zrtp_test_id_t g_alice_sid, g_bob_sid, g_pbxa_sid, g_pbxb_sid;
+static zrtp_test_id_t g_alice2pbx_channel, g_bob2pbx_channel;
+
+static void pbx_setup() {
+       zrtp_status_t s;
+
+       zrtp_test_endpoint_cfg_t endpoint_cfg;
+       zrtp_test_endpoint_config_defaults(&endpoint_cfg);
+
+       s = zrtp_test_endpoint_create(&endpoint_cfg, "Alice", &g_alice);
+       assert_int_equal(zrtp_status_ok, s);
+       assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_alice);
+
+       s = zrtp_test_endpoint_create(&endpoint_cfg, "Bob", &g_bob);
+       assert_int_equal(zrtp_status_ok, s);
+       assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_bob);
+
+       endpoint_cfg.zrtp.is_mitm = 1;
+       s = zrtp_test_endpoint_create(&endpoint_cfg, "PBX", &g_pbx);
+       assert_int_equal(zrtp_status_ok, s);
+       assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_pbx);
+}
+
+static void pbx_teardown() {
+       zrtp_test_endpoint_destroy(g_alice);
+       zrtp_test_endpoint_destroy(g_bob);
+       zrtp_test_endpoint_destroy(g_pbx);
+}
+
+
+static void prepare_alice_pbx_bob_setup(zrtp_test_session_cfg_t *alice_sconfig,
+                                                                               zrtp_test_session_cfg_t *bob_sconfig,
+                                                                               zrtp_test_session_cfg_t *pbxa_sconfig,
+                                                                               zrtp_test_session_cfg_t *pbxb_sconfig) {
+       zrtp_status_t s;
+
+       if (alice_sconfig) {
+               assert_non_null(pbxa_sconfig);
+
+               s = zrtp_test_session_create(g_alice, alice_sconfig, &g_alice_sid);
+               assert_int_equal(zrtp_status_ok, s);
+               assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_alice_sid);
+
+               s = zrtp_test_session_create(g_pbx, pbxa_sconfig, &g_pbxa_sid);
+               assert_int_equal(zrtp_status_ok, s);
+               assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_pbxa_sid);
+
+               s = zrtp_test_channel_create2(g_alice_sid, g_pbxa_sid, 0, &g_alice2pbx_channel);
+               assert_int_equal(zrtp_status_ok, s);
+               assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_alice2pbx_channel);
+       }
+
+       if (bob_sconfig) {
+               assert_non_null(pbxb_sconfig);
+
+               s = zrtp_test_session_create(g_bob, bob_sconfig, &g_bob_sid);
+               assert_int_equal(zrtp_status_ok, s);
+               assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_bob_sid);
+
+               s = zrtp_test_session_create(g_pbx,  pbxb_sconfig, &g_pbxb_sid);
+               assert_int_equal(zrtp_status_ok, s);
+               assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_pbxb_sid);
+
+               s = zrtp_test_channel_create2(g_bob_sid, g_pbxb_sid, 0, &g_bob2pbx_channel);
+               assert_int_equal(zrtp_status_ok, s);
+               assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_bob2pbx_channel);
+       }
+}
+
+static void cleanup_alice_pbx_bob_setup() {
+       zrtp_test_session_destroy(g_alice_sid);
+       zrtp_test_session_destroy(g_bob_sid);
+       zrtp_test_session_destroy(g_pbxa_sid);
+       zrtp_test_session_destroy(g_pbxb_sid);
+
+       zrtp_test_channel_destroy(g_alice2pbx_channel);
+       zrtp_test_channel_destroy(g_bob2pbx_channel);
+}
+
diff --git a/libs/libzrtp/test/enrollment_test.c b/libs/libzrtp/test/enrollment_test.c
new file mode 100644 (file)
index 0000000..5d54c55
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * libZRTP SDK library, implements the ZRTP secure VoIP protocol.
+ * Copyright (c) 2006-2009 Philip R. Zimmermann.  All rights reserved.
+ * Contact: http://philzimmermann.com
+ * For licensing and other legal details, see the file zrtp_legal.c.
+ *
+ * Viktor Krykun <v.krikun at zfoneproject.com>
+ */
+
+#include <setjmp.h>            /*chmockery dependency*/
+#include <stdio.h>             /*chmockery dependency*/
+#include <unistd.h>    /*for usleep*/
+
+#include "cmockery/cmockery.h"
+#include "test_engine.h"
+
+#include "enroll_test_helpers.c"
+
+static void enrollment_test() {
+       zrtp_status_t s;
+
+       zrtp_test_channel_info_t a2pbx_channel_info;
+       zrtp_test_session_cfg_t session_config, session_config_enroll;
+       zrtp_test_session_config_defaults(&session_config);
+       zrtp_test_session_config_defaults(&session_config_enroll);
+
+       session_config_enroll.is_enrollment = 1;
+
+       /**************************************************************************
+        * Enroll Alice to PBX and check triggered events.
+        */
+       prepare_alice_pbx_bob_setup(&session_config, NULL, &session_config_enroll, NULL);
+
+       /* Everything is ready. Let's start the stream and give it few seconds to switch secure. */
+       s = zrtp_test_channel_start(g_alice2pbx_channel);
+       assert_int_equal(zrtp_status_ok, s);
+
+       int i = 30;
+       for (; i>0; i--) {
+               usleep(100*1000);
+       }
+
+       s = zrtp_test_channel_get(g_alice2pbx_channel, &a2pbx_channel_info);
+       assert_int_equal(zrtp_status_ok, s);
+
+       /* Both, Alice and PBX should switch secure */
+       assert_true(a2pbx_channel_info.is_secure);
+
+       /* Alice should receive Enrollment notification */
+       zrtp_test_id_t alice2pbx_stream = zrtp_test_session_get_stream_by_idx(g_alice_sid, 0);
+       assert_true(zrtp_stream_did_event_receive(alice2pbx_stream, ZRTP_EVENT_IS_CLIENT_ENROLLMENT));
+
+       /* PBX streams should receive incoming enrollment notification */
+       zrtp_test_id_t pbx2alice_stream = zrtp_test_session_get_stream_by_idx(g_pbxa_sid, 0);
+       assert_true(zrtp_stream_did_event_receive(pbx2alice_stream, ZRTP_EVENT_NEW_USER_ENROLLED));
+
+       /* Clean-up */
+       cleanup_alice_pbx_bob_setup();
+
+
+       /**************************************************************************
+        * Try to make one more enrollment call. This time it should say "Already enrolled"
+        */
+       prepare_alice_pbx_bob_setup(&session_config, NULL, &session_config_enroll, NULL);
+
+       /* Everything is ready. Let's start the stream and give it few seconds to switch secure. */
+       s = zrtp_test_channel_start(g_alice2pbx_channel);
+       assert_int_equal(zrtp_status_ok, s);
+
+       i = 30;
+       for (; i>0; i--) {
+               usleep(100*1000);
+       }
+
+       s = zrtp_test_channel_get(g_alice2pbx_channel, &a2pbx_channel_info);
+       assert_int_equal(zrtp_status_ok, s);
+
+       assert_true(a2pbx_channel_info.is_secure);
+
+       /* Alice should receive Enrollment notification */
+       alice2pbx_stream = zrtp_test_session_get_stream_by_idx(g_alice_sid, 0);
+       assert_true(zrtp_stream_did_event_receive(alice2pbx_stream, ZRTP_EVENT_IS_CLIENT_ENROLLMENT));
+
+       /* PBX streams should receive incoming enrollment notification */
+       pbx2alice_stream = zrtp_test_session_get_stream_by_idx(g_pbxa_sid, 0);
+       assert_true(zrtp_stream_did_event_receive(pbx2alice_stream, ZRTP_EVENT_USER_ALREADY_ENROLLED));
+
+       // TODO: check if we have PBX secret cached
+       // TODO: test zrtp_is_user_enrolled()
+
+       // TODO: use zrtp_register_with_trusted_mitm()
+}
+
+int main(void) {
+       const UnitTest tests[] = {
+               unit_test_setup_teardown(enrollment_test, pbx_setup, pbx_teardown),
+       };
+
+       return run_tests(tests);
+}
diff --git a/libs/libzrtp/test/go_secure_test.c b/libs/libzrtp/test/go_secure_test.c
new file mode 100644 (file)
index 0000000..ab6740d
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * libZRTP SDK library, implements the ZRTP secure VoIP protocol.
+ * Copyright (c) 2006-2009 Philip R. Zimmermann.  All rights reserved.
+ * Contact: http://philzimmermann.com
+ * For licensing and other legal details, see the file zrtp_legal.c.
+ *
+ * Viktor Krykun <v.krikun at zfoneproject.com>
+ */
+
+#include <setjmp.h>            /*chmockery dependency*/
+#include <stdio.h>             /*chmockery dependency*/
+#include <unistd.h>    /*for usleep*/
+
+#include "cmockery/cmockery.h"
+#include "test_engine.h"
+
+static zrtp_test_id_t g_alice, g_bob;
+static zrtp_test_id_t g_alice_sid, g_bob_sid;
+static zrtp_test_id_t g_secure_audio_channel;
+
+static void setup() {
+       zrtp_status_t s;
+
+       zrtp_test_endpoint_cfg_t endpoint_cfg;
+       zrtp_test_endpoint_config_defaults(&endpoint_cfg);
+
+       s = zrtp_test_endpoint_create(&endpoint_cfg, "Alice", &g_alice);
+       assert_int_equal(zrtp_status_ok, s);
+       assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_alice);
+
+       s = zrtp_test_endpoint_create(&endpoint_cfg, "Bob", &g_bob);
+       assert_int_equal(zrtp_status_ok, s);
+       assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_bob);
+}
+
+static void teardown() {
+       zrtp_test_endpoint_destroy(g_alice);
+       zrtp_test_endpoint_destroy(g_bob);
+}
+
+static void go_secure_test() {
+       zrtp_status_t s;
+
+       zrtp_test_channel_info_t channel_info;
+       zrtp_test_session_cfg_t session_config;
+       zrtp_test_session_config_defaults(&session_config);
+
+       /*
+        * Create two test sessions, one for Alice and one for Bob and link them
+        * into test secure channel
+        */
+       s = zrtp_test_session_create(g_alice, &session_config, &g_alice_sid);
+       assert_int_equal(zrtp_status_ok, s);
+       assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_alice_sid);
+
+       s = zrtp_test_session_create(g_bob, &session_config, &g_bob_sid);
+       assert_int_equal(zrtp_status_ok, s);
+       assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_bob_sid);
+
+       s = zrtp_test_channel_create2(g_alice_sid, g_bob_sid, 0, &g_secure_audio_channel);
+       assert_int_equal(zrtp_status_ok, s);
+       assert_int_not_equal(ZRTP_TEST_UNKNOWN_ID, g_secure_audio_channel);
+
+       /* Everything is ready. Let's start the stream and give it few seconds to switch secure. */
+       s = zrtp_test_channel_start(g_secure_audio_channel);
+       assert_int_equal(zrtp_status_ok, s);
+
+       int i = 30;
+       for (; i>0; i--) {
+               usleep(100*1000);
+       }
+
+       s = zrtp_test_channel_get(g_secure_audio_channel, &channel_info);
+       assert_int_equal(zrtp_status_ok, s);
+
+       /* Both, Alice and Bob should switch secure */
+       assert_true(channel_info.is_secure);
+
+       zrtp_test_session_destroy(g_alice_sid);
+       zrtp_test_session_destroy(g_bob_sid);
+
+       zrtp_test_channel_destroy(g_secure_audio_channel);
+}
+
+int main(void) {
+       const UnitTest tests[] = {
+               unit_test_setup_teardown(go_secure_test, setup, teardown),
+       };
+
+       return run_tests(tests);
+}
diff --git a/libs/libzrtp/test/pc/zrtp_test_core.c b/libs/libzrtp/test/pc/zrtp_test_core.c
deleted file mode 100644 (file)
index ae3a7ec..0000000
+++ /dev/null
@@ -1,866 +0,0 @@
-/*
- * libZRTP SDK library, implements the ZRTP secure VoIP protocol.
- * Copyright (c) 2006-2009 Philip R. Zimmermann.  All rights reserved.
- * Contact: http://philzimmermann.com
- * For licensing and other legal details, see the file zrtp_legal.c.
- * 
- * Viktor Krykun <v.krikun at zfoneproject.com> 
- */
-
-#include "zrtp.h"
-
-#include "zrtp_test_core.h"
-#include "zrtp_test_queue.h"
-
-#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE)
-#include <windows.h>
-#elif (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_LINUX)
-#include <pthread.h>
-#include <string.h>
-#endif
-
-#define        _ZTU_ "TEST"
-#define        ZRTP_TEST_PACKET_MAX_SIZE       256
-#define        ZRTP_TEST_STREAMS_COUNT         1
-
-#define ZRTP_ENABLE_TEST                       0
-
-extern uint8_t hash_word_list_odd[256][12];
-extern uint8_t hash_word_list_even[256][10];
-
-/*! Global data storage */
-typedef struct zrtp_test_global
-{
-       mlist_t                         channels_head;  /*! List of test channels*/
-       zrtp_mutex_t*           channels_protector;     /*! Protector from list modifications */        
-       unsigned char           is_log_enabled; /*! Allows debug messages logging */
-       unsigned                        packets_rate;   /*! Delay in miliseconds between RTP injection */       
-       unsigned                        channels_count; /*! Active channels count */
-       unsigned                        secure_count;   /*! Active channels count */
-       zrtp_queue_t*           queue;                  /*! Queue which emulate communication channel between ZRTP endpoints */
-       unsigned char           is_running;             /*! Main test loop work while this is not 0 */
-} zrtp_test_global_t;
-
-zrtp_test_global_t             test_global;    /*! zrtp test global data */
-zrtp_global_t*                 zrtp_global;    /*! libzrtp global data */
-
-
-typedef struct zrtp_test_session       zrtp_test_session_t;
-typedef struct zrtp_test_stream                zrtp_test_stream_t;
-typedef struct zrtp_test_channel       zrtp_test_channel_t;
-
-#define        ZRTP_TEST_PACKET_HEADER_LENGTH 16
-
-
-typedef struct zrtp_test_packet
-{
-       uint32_t                        is_rtp;                 /*! Defines is packet RTP or RTCP */
-       uint32_t                        length;                 /*! Packet Length in bytes */
-       char                            body[1024];             /*! Packet body */
-} zrtp_test_packet_t;
-
-struct zrtp_test_stream
-{
-       zrtp_stream_t*          zrtp_stream;    /*! ZRTP stream associated test stream */
-       zrtp_test_session_t* session;           /*! Pointer to the parent test session */
-       uint16_t                        seq;                    /*! RTP sequence number for media packets construction */
-       uint32_t                        ssrc;                   /*! RTP local SSRC for media packets exchanging */
-       uint32_t                        peer_ssrc;              /*! RTP remote SSRC for media packets exchanging */
-};
-
-struct zrtp_test_session
-{      
-       zrtp_test_stream_t      streams[ZRTP_MAX_STREAMS_PER_SESSION]; /*! Streams array */
-       unsigned                        streams_count;  /*! Active streams counter */   
-       zrtp_session_t*         zrtp_session;   /*! ZRTP session associated test session */
-       zrtp_test_channel_t *channel;
-       mlist_t                         _list;
-};
-
-struct zrtp_test_channel
-{
-       zrtp_test_channel_id_t  id;                     /*! Channel ID*/
-       zrtp_test_session_t             ses_left;       /*! Left test session */
-       zrtp_test_session_t             ses_right;      /*! Right test session */
-       mlist_t                                 _mlist;
-};
-
-
-zrtp_test_channel_t* find_channel_by_index(zrtp_test_channel_id_t chan_id);
-zrtp_test_channel_t* find_channel_with_closest_index(zrtp_test_channel_id_t chan_id);
-zrtp_test_stream_t*  find_peer_stream_by_ssrc(uint32_t ssrc);
-
-
-/*============================================================================*/
-/*     ZRTP Interfaces                                                                                                           */
-/*============================================================================*/
-
-static void on_zrtp_protocol_event(zrtp_stream_t *ctx, zrtp_protocol_event_t event)
-{
-}
-
-static void on_zrtp_security_event(zrtp_stream_t *ctx, zrtp_security_event_t event)
-{
-}
-                                                                  
-static void on_zrtp_secure(zrtp_stream_t *ctx)
-{
-       zrtp_test_stream_t *stream = (zrtp_test_stream_t*) zrtp_stream_get_userdata(ctx);
-       zrtp_test_channel_t *channel = stream->session->channel;
-       unsigned i = 0;
-       unsigned char not_secure = 0;
-               
-       ZRTP_LOG(1, (_ZTU_,"Stream is SECURE ssrc=%u ctx=%d\n", ctx->media_ctx.ssrc, ctx));
-       
-       for (i=0; i<channel->ses_left.streams_count; i++) {
-               if (ZRTP_STATE_SECURE != channel->ses_left.streams[i].zrtp_stream->state) {
-                       not_secure = 1;
-               }
-       }               
-       if (0 == not_secure) {
-               for (i=0; i<channel->ses_right.streams_count; i++) {
-                       if (ZRTP_STATE_SECURE != channel->ses_right.streams[i].zrtp_stream->state) {
-                               not_secure = 1;
-                       }
-               }
-       }       
-       
-       if (0 == not_secure) {
-               zrtp_session_info_t session_info;
-               zrtp_stream_info_t a_stream_info;
-               
-               test_global.secure_count++;
-               
-               ZRTP_LOG(1, (_ZTU_,"===================================================\n"));
-               ZRTP_LOG(1, (_ZTU_,"Entire Channel is SECURE. Total Secure count=%d\n", test_global.secure_count));
-               ZRTP_LOG(1, (_ZTU_,"===================================================\n"));
-               
-               zrtp_session_get(channel->ses_left.zrtp_session, &session_info);                
-               zrtp_stream_get(channel->ses_left.streams[0].zrtp_stream , &a_stream_info);
-               
-               zrtp_log_print_sessioninfo(&session_info);
-               zrtp_log_print_streaminfo(&a_stream_info);              
-       }
-}
-
-static int on_send_packet(const zrtp_stream_t* ctx, char* message, unsigned int length)
-{
-       zrtp_queue_elem_t* elem = zrtp_sys_alloc(sizeof(zrtp_queue_elem_t));
-       if (elem) {             
-               zrtp_test_packet_t* packet = (zrtp_test_packet_t*) elem->data;
-               elem->size = length;
-                               
-               packet->is_rtp = 1;
-               packet->length = length;
-               zrtp_memcpy(packet->body, message, length);
-                               
-               ZRTP_LOG(1, (_ZTU_,"\tSend message to ssrc=%u length=%d\n", ctx->media_ctx.ssrc, length));
-               zrtp_test_queue_push(test_global.queue, elem);
-               return zrtp_status_ok;
-       } else {
-               return zrtp_status_alloc_fail;
-       }
-} 
-
-void zrtp_def_get_cache_path(char *path, uint32_t length)
-{
-#if   (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE)
-       strncpy_s(path, length, "./zrtp_test_cache.dat", length);
-#else
-       strncpy(path, "./zrtp_test_cache.dat", length);
-#endif
-}
-
-
-/*============================================================================*/
-/*     Sessions Life-Cycle Logic                                                                                         */
-/*============================================================================*/
-
-/*----------------------------------------------------------------------------*/
-#if   (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE)
-DWORD WINAPI process_incoming(void *param)
-#else
-void *process_incoming(void *param)
-#endif
-{
-       ZRTP_LOG(1, (_ZTU_,"======> STARTING Incoming processor\n"));
-       while (test_global.is_running)
-       {
-               zrtp_test_packet_t* packet = NULL;
-               zrtp_queue_elem_t* elem = NULL;
-               zrtp_status_t s = zrtp_status_fail;
-               zrtp_test_stream_t *stream = NULL;
-               int is_protocol = 0;
-               
-               /* Get packet from the "Network" and find aapropriate stream to process it */
-               elem = zrtp_test_queue_pop(test_global.queue);
-               packet = (zrtp_test_packet_t*) elem->data;
-               
-               /* We have ssrc in the packet, which indetifies stream that had send it to us.
-                * so now we have to find appropriate stream which has to process that packet.
-                */
-               if (packet->is_rtp) {
-                       ZRTP_UNALIGNED(zrtp_rtp_hdr_t) *hdr = (zrtp_rtp_hdr_t*) (packet->body);
-                       if (ZRTP_PACKETS_MAGIC == zrtp_ntoh32(hdr->ts))  {
-                               is_protocol      = 1;
-                               ZRTP_LOG(1, (_ZTU_,"\n"));
-                       }       
-                       stream = find_peer_stream_by_ssrc(hdr->ssrc);
-               } else {
-                       ZRTP_UNALIGNED(zrtp_rtcp_hdr_t) *hdr = (zrtp_rtcp_hdr_t*) (packet->body);
-                       stream = find_peer_stream_by_ssrc(hdr->ssrc);           
-               }
-                               
-               if (!stream) {
-                       zrtp_sys_free(elem);
-                       ZRTP_LOG(1, (_ZTU_,"process_incoming(): ERROR! can't found peer stream!\n"));
-                       continue;
-               }                       
-               
-               /*
-                * Process incoming packet by libzrtp. Is this a RTP media packet - copy it to the buffer
-                * to print out later.
-                */
-               if (packet->is_rtp) {           
-                       s = zrtp_process_srtp(stream->zrtp_stream, packet->body, &packet->length);                      
-               } else {        
-                       s = zrtp_process_srtcp(stream->zrtp_stream, packet->body, &packet->length);
-               }
-               
-               
-               if (!is_protocol)
-               {
-                       char *body;
-                       if (packet->is_rtp) {
-                               body = packet->body + sizeof(zrtp_rtp_hdr_t);
-                               body[packet->length - sizeof(zrtp_rtp_hdr_t)] = 0;                              
-                       } else {
-                               body = packet->body + sizeof(zrtp_rtcp_hdr_t); 
-                               body[packet->length - sizeof(zrtp_rtcp_hdr_t)] = 0;
-                       }
-                       
-                       switch (s)
-                       {
-                       case zrtp_status_ok: {
-                               ZRTP_LOG(1, (_ZTU_,"Incoming: (%s) [%p:ssrc=%u] INPUT. <%s> decrypted %d bytes.\n",
-                                                       zrtp_log_state2str(stream->zrtp_stream->state), stream->zrtp_stream,  stream->ssrc, body, packet->length));
-                       } break;
-                       
-                       case zrtp_status_drop: {
-                               ZRTP_LOG(1, (_ZTU_,"Incoming: (%s) [%p:ssrc=%u] INPUT DROPPED. <%s>\n",
-                                                       zrtp_log_state2str(stream->zrtp_stream->state), stream->zrtp_stream, stream->ssrc, body));
-                       } break;
-                       
-                       case zrtp_status_fail: {
-                               ZRTP_LOG(1, (_ZTU_,"Incoming: (%s) [%p:ssrc=%u] DECRYPT FAILED. <%s>\n",
-                                                       zrtp_log_state2str(stream->zrtp_stream->state), stream->zrtp_stream, stream->ssrc, body));
-                       } break;
-                               
-                       default:
-                               break;
-                       }
-               }
-               
-               zrtp_sys_free(elem);
-               
-               /* 
-                * When zrtp_stream is in the pending clear state and other side wants to send plain
-                * traffic. We have to call zrtp_clear_stream().
-                */
-               if (stream->zrtp_stream->state == ZRTP_STATE_PENDINGCLEAR) {
-                       zrtp_stream_clear(stream->zrtp_stream);
-               }               
-       } /* while is running */
-       
-#if   (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE)
-       return 0;
-#else
-       return NULL;
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-#if   (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE)
-DWORD WINAPI process_outgoing(void *param)
-#else
-void *process_outgoing(void *param)
-#endif
-{      
-       unsigned packets_counter = 0;
-       
-       ZRTP_LOG(1, (_ZTU_,"======> STARTING Outgoing processor\n"));
-       while (test_global.is_running)
-       {               
-               zrtp_test_channel_id_t channel_id = 0;
-               zrtp_test_channel_t* channel = NULL;
-               zrtp_test_session_t* session = NULL;            
-               unsigned i;
-                               
-               zrtp_sleep(test_global.packets_rate);
-
-               if ((0 == test_global.channels_count) || (0 == test_global.secure_count)) {
-                       continue;
-               }
-               
-               /* Get random channel to operate with and select random peer */
-               zrtp_randstr(zrtp_global, (unsigned char*)&channel_id, sizeof(zrtp_test_channel_id_t));
-               channel = find_channel_with_closest_index(channel_id);
-               if (!channel) {
-                       continue;
-               }
-               
-               ZRTP_LOG(1, (_ZTU_,"\n"));
-               ZRTP_LOG(1, (_ZTU_,"Out. Generate packet by channel N=%u and %s session.\n",
-                                        channel->id, ((channel_id % 100) > 50) ? "RIGHT": "LEFT"));
-               
-               session = ((channel_id % 100) > 50) ? &channel->ses_right : &channel->ses_left;
-               
-               /* Generate RTP or RTCP packet for every stream within the session */
-               for (i=0; i<session->streams_count; i++)
-               {
-                       zrtp_status_t s = zrtp_status_fail;
-                       zrtp_test_packet_t* packet;
-                       zrtp_queue_elem_t* elem;
-                       zrtp_test_stream_t* stream = &session->streams[i];
-                       char* word = NULL;
-                       
-                       elem = zrtp_sys_alloc(sizeof(zrtp_queue_elem_t));
-                       if (!elem) {
-                               break;
-                       }
-                       packet = (zrtp_test_packet_t*) elem->data;
-                       packet->is_rtp = (packets_counter++ % 20); /* Every 20-th packet is RTCP */                     
-                       
-                       /*
-                        * Construct RTP/RTCP Packet
-                        */
-                       if (packet->is_rtp)
-                       {
-                               ZRTP_UNALIGNED(zrtp_rtp_hdr_t) *rtp_hdr = (zrtp_rtp_hdr_t*)packet->body;                                
-                               
-                               /* Fill RTP Header according to the specification */
-                               zrtp_memset(rtp_hdr, 0, sizeof(zrtp_rtp_hdr_t));
-                               rtp_hdr->version = 2;                   /* Current RTP version 2 */
-                               rtp_hdr->pt = 0;                                /* PCMU padding type */    
-                               rtp_hdr->ssrc = stream->ssrc;   /* Use ssrc for addressing like in real RTP */
-                               if (stream->seq >= 0xFFFF) {
-                                       stream->seq = 0;
-                               }
-                               rtp_hdr->seq = zrtp_hton16(stream->seq++);                              
-                               rtp_hdr->ts = zrtp_hton32((uint32_t)(zrtp_time_now()/1000));
-
-                               /* Get RTP body from PGP words lists */
-                               word = (char*)(i ? hash_word_list_odd[packets_counter % 256] : hash_word_list_even[packets_counter % 256]);
-                               
-                               zrtp_memcpy(packet->body + sizeof(zrtp_rtp_hdr_t), word, (uint32_t)strlen(word));
-                               packet->length = sizeof(zrtp_rtp_hdr_t) + (uint32_t)strlen(word);
-
-                               /* Process RTP media with libzrtp */
-                               s = zrtp_process_rtp(stream->zrtp_stream, packet->body, &packet->length);
-                       }
-                       else
-                       {
-                               ZRTP_UNALIGNED(zrtp_rtcp_hdr_t) *rtcp_hdr = (zrtp_rtcp_hdr_t*)packet->body;
-                               
-                               /* Fill RTCP Header according to the specification */
-                               rtcp_hdr->rc = 0;
-                               rtcp_hdr->version = 2;
-                               rtcp_hdr->ssrc = stream->ssrc;
-                               
-                               /* Get RTP body from PGP words lists. Put RTCP marker at the beginning */
-                               zrtp_memcpy(packet->body + sizeof(zrtp_rtcp_hdr_t), "RTCP", 4);
-                               word = (char*)( i ? hash_word_list_odd[packets_counter % 256] : hash_word_list_even[packets_counter % 256]);
-                               
-                               zrtp_memcpy(packet->body + sizeof(zrtp_rtcp_hdr_t) + 4, word, (uint32_t)strlen(word));
-                               packet->length = sizeof(zrtp_rtcp_hdr_t) + (uint32_t)strlen(word) + 4;
-                               /* RTCP packets sould be 32 byes aligned */
-                               packet->length += (packet->length % 4) ? (4 - packet->length % 4) : 0;
-
-                               /* Process RTCP control with libzrtp */
-                               s = zrtp_process_rtcp(stream->zrtp_stream, packet->body, &packet->length);
-                       }
-
-                       /* Handle zrtp_process_xxx() instructions */
-                       switch (s)
-                       {
-                       /* Put the packet to the queue ==> send packet to the other side pear */
-                       case zrtp_status_ok: {                                                  
-                               ZRTP_LOG(3, (_ZTU_,"Outgoing: (%s) [%p:ssrc=%u] OUTPUT. <%s%s> encrypted %d bytes.\n",
-                                                       zrtp_log_state2str(stream->zrtp_stream->state), stream->zrtp_stream, stream->ssrc, packet->is_rtp ? "" : "RTCP", word, packet->length));
-                               zrtp_test_queue_push(test_global.queue, elem);                                                                                  
-                       } break;
-                       
-                       case zrtp_status_drop: {
-                               ZRTP_LOG(1, (_ZTU_,"Outgoing: (%s) [%p:ssrc=%u] OUTPUT DROPPED.\n",
-                                                       zrtp_log_state2str(stream->zrtp_stream->state), stream->zrtp_stream, stream->ssrc));
-                       } break;
-                               
-                       case zrtp_status_fail: {
-                               ZRTP_LOG(1, (_ZTU_,"Outgoing: (%s) [%p:ssrc=%u] ENCRYPT FAILED.\n",
-                                                       zrtp_log_state2str(stream->zrtp_stream->state), stream->zrtp_stream, stream->ssrc));
-                       }       break;
-                       
-                       default:
-                               break;
-                       }
-                                               
-                       if (zrtp_status_ok != s) {
-                               zrtp_sys_free(packet);
-                       }
-                       
-               } /* for (every stream within the session) */
-       } /* while is running */
-       
-#if   (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE)
-       return 0;
-#else
-       return NULL;
-#endif
-}
-
-/*----------------------------------------------------------------------------*/
-static zrtp_status_t init_test_session( zrtp_test_session_t *session,
-                                                                           zrtp_profile_t *zrtp_profile,
-                                                                           unsigned nstreams)
-{
-       unsigned i = 0;
-       g_zrtp_cfg zid;
-       zrtp_status_t s = zrtp_status_fail;
-       
-       session->streams_count = nstreams;
-       
-       /* Allocate ZRTP session */
-       zrtp_randstr(zrtp_global, (unsigned char*)&zid, sizeof(g_zrtp_cfg));
-       
-       ZRTP_LOG(3, (_ZTU_,"INITIALIZE NEW SESSION ctx=%p:\n", session));
-       ZRTP_LOG(3, (_ZTU_,"---------------------------------------------------\n"));
-       
-       s = zrtp_session_init(zrtp_global, zrtp_profile, zid, 1, &session->zrtp_session);       
-       if (zrtp_status_ok != s) {      
-               ZRTP_LOG(3, (_ZTU_,"ERROR! can't initalize ZRTP session d=%d.\n", s));
-               return s;
-       }
-       
-       zrtp_session_set_userdata(session->zrtp_session, session);
-       
-       ZRTP_LOG(3, (_ZTU_,"Attach %d ZRTP streams.\n", session->streams_count));
-       /* ZRTP session is ready for use. Now it's time to attach streams to it */
-       for (i=0; i<session->streams_count; i++)
-       {
-               zrtp_test_stream_t *stream = &session->streams[i];
-               
-               /* Create random sequence number and ssrc for packets generation */
-               zrtp_randstr(zrtp_global, (unsigned char*)&stream->seq, sizeof(stream->seq));
-               zrtp_randstr(zrtp_global, (unsigned char*)&stream->ssrc, sizeof(stream->ssrc));
-               
-               ZRTP_LOG(3, (_ZTU_,"Created stream N%d ssrc=%u seq=%d ctx=%p\n", i, stream->ssrc, stream->seq, stream));
-               
-               /* Attach zrtp_stream to zrtp_session */
-               s = zrtp_stream_attach(session->zrtp_session, &stream->zrtp_stream);
-               if (zrtp_status_ok != s) {
-                       ZRTP_LOG(3, (_ZTU_,"ERROR! can't attach ZRTP stream.\n"));
-                       break;
-               }
-               zrtp_stream_set_userdata(stream->zrtp_stream, stream);
-               stream->session = session;
-       }
-       
-       if (i != session->streams_count) {
-               zrtp_session_down(session->zrtp_session);
-               return zrtp_status_fail;                
-       }
-       
-       return zrtp_status_ok;
-};
-
-/*----------------------------------------------------------------------------*/
-int zrtp_test_channel_create( const zrtp_test_channel_config_t* config,
-                                                         zrtp_test_channel_id_t* chan_id)
-{
-       zrtp_status_t s = zrtp_status_fail;
-       zrtp_test_channel_t* channel = NULL;
-       unsigned streams_number = 1;
-       
-       
-       /*
-        * Create two connection for each side of the call.
-        * They will have the same id in order to simplify calls managing.
-        */
-       channel = zrtp_sys_alloc(sizeof(zrtp_test_channel_t));
-       if (!channel) {
-               return -1;
-       }       
-       zrtp_memset(channel, 0, sizeof(zrtp_test_channel_t));
-       
-       /* Generate new unique ID for the channel */
-       zrtp_randstr(zrtp_global, (unsigned char*)chan_id, sizeof(zrtp_test_channel_id_t));
-       
-       ZRTP_LOG(1, (_ZTU_,"=====> CREATE NEW CHANNEL ID=%u ctx=%p.\n", chan_id, channel));
-       
-       /*
-        * Alloacte and initalize ZRTP crypto stuffs
-        */
-       do {
-               zrtp_profile_t zrtp_profile;
-               unsigned i = 0;
-               
-               /*
-                * Use default ZRTP configuration with slitely changes:
-                * - enable "allowclear" to be able to test more scenarios
-                */
-               zrtp_profile_defaults(&zrtp_profile, zrtp_global);
-               zrtp_profile.allowclear = 1;
-               zrtp_profile.autosecure = 1;
-               
-               channel->ses_left.streams_count = streams_number;
-#if (ZRTP_ENABLE_TEST == 1)
-               zrtp_profile.pk_schemes[0] = ZRTP_PKTYPE_EC384P;
-               zrtp_profile.pk_schemes[1] = ZRTP_PKTYPE_DH3072;
-               zrtp_profile.pk_schemes[2] = ZRTP_PKTYPE_MULT;
-               zrtp_profile.pk_schemes[3] = 0;         
-#endif         
-               s = init_test_session(&channel->ses_left, &zrtp_profile, 1);
-               if (zrtp_status_ok != s) {
-                       break;
-               }
-               channel->ses_left.channel = channel;
-               
-               channel->ses_right.streams_count = streams_number;
-#if (ZRTP_ENABLE_TEST == 1)    
-               zrtp_profile.autosecure = 1;
-               zrtp_profile.pk_schemes[0] = ZRTP_PKTYPE_EC384P;
-               zrtp_profile.pk_schemes[1] = ZRTP_PKTYPE_DH2048;
-               zrtp_profile.pk_schemes[2] = ZRTP_PKTYPE_DH3072;
-               zrtp_profile.pk_schemes[3] = ZRTP_PKTYPE_MULT;
-               zrtp_profile.pk_schemes[4] = 0;
-#endif
-               s = init_test_session(&channel->ses_right, &zrtp_profile, 1);
-               if (zrtp_status_ok != s) {
-                       break;
-               }
-               channel->ses_right.channel = channel;
-               
-               /* Make cross-references to allow left stream to communicate with the right one. */
-               for (i=0; i<streams_number; i++) {
-                       channel->ses_left.streams[i].peer_ssrc = channel->ses_right.streams[i].ssrc;
-                       channel->ses_right.streams[i].peer_ssrc = channel->ses_left.streams[i].ssrc;
-               }
-       } while (0);
-       
-       if (zrtp_status_ok != s) {
-               zrtp_sys_free(channel);
-       } else {
-               channel->id = *chan_id;         
-               zrtp_mutex_lock(test_global.channels_protector);
-               mlist_add(&test_global.channels_head, &channel->_mlist);
-               zrtp_mutex_unlock(test_global.channels_protector);
-       }
-       
-       test_global.channels_count++;
-        
-       return s;
-}
-
-/*----------------------------------------------------------------------------*/
-static void down_test_session(zrtp_test_session_t *session)
-{
-       zrtp_session_down(session->zrtp_session);
-};
-
-int zrtp_test_channel_delete(zrtp_test_channel_id_t chan_id)
-{
-       zrtp_test_channel_t* channel = find_channel_by_index(chan_id);
-       if (channel)
-       {
-               test_global.channels_count--;
-               
-               zrtp_mutex_lock(test_global.channels_protector);
-               mlist_del(&channel->_mlist);
-               zrtp_mutex_unlock(test_global.channels_protector);
-               
-               down_test_session(&channel->ses_left);
-               down_test_session(&channel->ses_right);
-               
-               zrtp_sys_free(channel);
-               return 0;
-       } else {
-               return -1;
-       }
-}
-
-/*----------------------------------------------------------------------------*/
-typedef enum
-{
-       TEST_ACTION_START = 0,
-       TEST_ACTION_SECURE,
-       TEST_ACTION_CLEAR,
-       TEST_ACTION_STOP
-} zrtp_test_session_action_t;
-
-static void test_session_do_action(zrtp_test_session_t *session, zrtp_test_session_action_t action)
-{
-       unsigned i = 0; 
-       if (session->zrtp_session)
-       {
-               for (i=0; i<session->streams_count; i++) {
-                       switch (action) {
-                       case TEST_ACTION_START:
-                       {
-                               char buff[65];
-                               ZRTP_LOG(1, (_ZTU_,"=====> START TEST SESSION ID=%u ctx=%p.\n", session->channel->id, session->channel));                               
-                               zrtp_stream_start(session->streams[i].zrtp_stream, zrtp_ntoh32(session->streams[i].ssrc));                                      
-                               zrtp_signaling_hash_get(session->streams[i].zrtp_stream, buff, sizeof(buff));                                   
-                               break;
-                       }
-                       case TEST_ACTION_STOP:
-                               ZRTP_LOG(1, (_ZTU_,"=====> STOP TEST SESSION ID=%u ctx=%p.\n", session->channel->id, session->channel));
-                               zrtp_stream_stop(session->streams[i].zrtp_stream);
-                               break;
-                       case TEST_ACTION_SECURE:
-                               ZRTP_LOG(1, (_ZTU_,"=====> SECURE TEST SESSION ID=%u ctx=%p.\n", session->channel->id, session->channel));
-                               zrtp_stream_secure(session->streams[i].zrtp_stream);
-                               break;
-                       case TEST_ACTION_CLEAR:
-                               ZRTP_LOG(1, (_ZTU_,"=====> CLEAR TEST SESSION ID=%u ctx=%p.\n", session->channel->id, session->channel));
-                               zrtp_stream_clear(session->streams[i].zrtp_stream);
-                               break;
-                       }                       
-               }
-       }
-};
-
-static int test_channel_do_action(zrtp_test_channel_id_t chan_id, zrtp_test_session_action_t action)
-{
-       zrtp_test_channel_t* channel = find_channel_by_index(chan_id);
-       if (channel) {
-               test_session_do_action(&channel->ses_left, action);
-               test_session_do_action(&channel->ses_right, action);
-               return 0;
-       } else {
-               return -1;
-       }
-}
-
-int zrtp_test_channel_start(zrtp_test_channel_id_t chan_id) {
-       return test_channel_do_action(chan_id, TEST_ACTION_START);
-}
-
-int zrtp_test_channel_secure(zrtp_test_channel_id_t chan_id) {
-       return test_channel_do_action(chan_id, TEST_ACTION_SECURE);
-}
-
-int zrtp_test_channel_clear(zrtp_test_channel_id_t chan_id) {
-       return test_channel_do_action(chan_id, TEST_ACTION_CLEAR);
-}
-
-int zrtp_test_channel_stop(zrtp_test_channel_id_t chan_id) {
-       return test_channel_do_action(chan_id, TEST_ACTION_STOP);
-}
-
-
-/*============================================================================*/
-/*     Test Routine                                                                                                                      */
-/*============================================================================*/
-
-/*---------------------------------------------------------------------------*/
-static int start_processors(int count)
-{
-       int32_t i;
-       for (i = 0; i<count; i++)
-       {
-               if (0 != zrtp_thread_create(process_incoming, NULL)) {
-                       return -1;
-               }
-               if (0 != zrtp_thread_create(process_outgoing, NULL)) {
-                       return -1;
-               }
-       }
-       
-       return 0;
-}
-
-int zrtp_test_zrtp_init()
-{
-       int result = -1;
-       zrtp_status_t s = zrtp_status_ok;
-       zrtp_config_t zrtp_config;
-       
-       ZRTP_LOG(1, (_ZTU_,"=====>Start ZRTP Test-Unite Core initalization.\n"));
-       
-       zrtp_memset(&test_global, 0, sizeof(test_global));
-       
-       ZRTP_LOG(1, (_ZTU_,"Create internal components...\n"));
-       do {    
-               /* Create global objects: channels list and communication queue */
-               init_mlist(&test_global.channels_head);
-               
-               s = zrtp_mutex_init(&test_global.channels_protector);
-               if (zrtp_status_ok != s) {
-                       ZRTP_LOG(1, (_ZTU_,"ERROR! Can't create channels protector %d\n", s));
-                       break;
-               }
-               
-               s = zrtp_test_queue_create(&test_global.queue);
-               if (zrtp_status_ok != s) {
-                       ZRTP_LOG(1, (_ZTU_,"ERROR! Can't create global queue: %s\n", s));
-                       break;
-               }
-               
-               /* Start several threads to process test zrtp channels */
-               test_global.is_running = 1;
-               result = start_processors(ZRTP_TEST_STREAMS_COUNT);
-               if (0 != result) {
-                       break;
-               }
-               
-               ZRTP_LOG(1, (_ZTU_,"Configuring and Initalizing ZRTP engine...\n"));
-               /* Reset  global values to defaults */
-               test_global.is_log_enabled      = 1;
-               test_global.packets_rate        = 500;
-               test_global.channels_count      = 0;
-               
-               /* Initalize ZRTP Engine */
-               zrtp_config_defaults(&zrtp_config);
-               zrtp_config.lic_mode = ZRTP_LICENSE_MODE_ACTIVE;
-               zrtp_memcpy(zrtp_config.client_id, "ZRTP Test Unite!", 16);
-               
-               zrtp_config.cb.event_cb.on_zrtp_secure                  = on_zrtp_secure;
-               zrtp_config.cb.event_cb.on_zrtp_security_event  = on_zrtp_security_event;
-               zrtp_config.cb.event_cb.on_zrtp_protocol_event  = on_zrtp_protocol_event;
-               zrtp_config.cb.misc_cb.on_send_packet                   = on_send_packet;
-               
-               s = zrtp_init(&zrtp_config, &zrtp_global);
-               if (zrtp_status_ok != s) {
-                       ZRTP_LOG(1, (_ZTU_,"ERROR! zrtp_init() failed with status=%d.\n", s));
-                       break;
-               }
-               
-               result = 0;
-       } while (0);
-       
-       if (0 != result) {
-               if (!test_global.channels_protector) {
-                       zrtp_mutex_destroy(test_global.channels_protector);
-               }
-               if (!test_global.queue) {
-                       zrtp_test_queue_destroy(test_global.queue);
-               }
-       }
-       
-       return result;
-}
-
-/*----------------------------------------------------------------------------*/
-int zrtp_test_zrtp_down()
-{
-       mlist_t* node = NULL,* tmp = NULL;
-       
-       ZRTP_LOG(1, (_ZTU_,"=====> Destroying ZRTP Test Application:\n"));
-       ZRTP_LOG(1, (_ZTU_,"Stop all running threads.\n"));
-       
-       /* Stop Main Processing Loop */
-       test_global.is_running = 0;
-       
-       ZRTP_LOG(1, (_ZTU_,"Destroy all active connections.\n"));
-       /* Stop and destroy all active sessions */      
-       zrtp_mutex_lock(test_global.channels_protector);
-       mlist_for_each_safe(node, tmp, &test_global.channels_head) {
-               zrtp_test_channel_t* result = (zrtp_test_channel_t*) mlist_get_struct(zrtp_test_channel_t, _mlist, node);
-               zrtp_test_channel_delete(result->id);           
-       }
-       zrtp_mutex_unlock(test_global.channels_protector);
-       
-       ZRTP_LOG(1, (_ZTU_,"Destroy ZRTP Engine.\n"));
-       /* Destroy libzrtp and all utility components */
-       zrtp_down(zrtp_global);
-       
-        if (!test_global.channels_protector) {
-               zrtp_mutex_destroy(test_global.channels_protector);
-       }
-       if (!test_global.queue) {
-               zrtp_test_queue_destroy(test_global.queue);
-       }
-       
-       return 0;
-}
-
-/*----------------------------------------------------------------------------*/
-zrtp_test_channel_t* find_channel_by_index(zrtp_test_channel_id_t chan_id)
-{
-       unsigned char is_found = 0;
-       mlist_t* node = NULL,* tmp = NULL;
-       zrtp_test_channel_t* result = NULL;
-       
-       zrtp_mutex_lock(test_global.channels_protector);
-       mlist_for_each_safe(node, tmp, &test_global.channels_head) {
-               result = (zrtp_test_channel_t*) mlist_get_struct(zrtp_test_channel_t, _mlist, node);
-               if (result->id == chan_id) {
-                       is_found = 1;
-                       break;
-               }
-       }
-       zrtp_mutex_unlock(test_global.channels_protector);
-       
-       return (is_found) ? result : NULL;
-}
-
-zrtp_test_channel_t* find_channel_with_closest_index(zrtp_test_channel_id_t chan_id)
-{
-       unsigned char is_found = 0;
-       mlist_t* node = NULL,* tmp = NULL;
-       zrtp_test_channel_t* result = NULL;
-       zrtp_test_channel_t* left = NULL;
-       
-       zrtp_mutex_lock(test_global.channels_protector);
-       mlist_for_each_safe(node, tmp, &test_global.channels_head) {
-               result = (zrtp_test_channel_t*) mlist_get_struct(zrtp_test_channel_t, _mlist, node);
-               if (result->id > chan_id) {
-                       is_found = 1;
-                       break;
-               } else {
-                       left = result;
-               }
-       }
-       zrtp_mutex_unlock(test_global.channels_protector);
-       
-       return (is_found) ? result : left;
-}
-
-zrtp_test_stream_t*  find_peer_stream_by_ssrc(uint32_t ssrc)
-{
-       unsigned char is_found = 0;
-       mlist_t *node = NULL, *tmp = NULL;
-       zrtp_test_stream_t *result = NULL;
-       
-       zrtp_mutex_lock(test_global.channels_protector);
-       mlist_for_each_safe(node, tmp, &test_global.channels_head)
-       {
-               zrtp_test_channel_t *channel = (zrtp_test_channel_t*) mlist_get_struct(zrtp_test_channel_t, _mlist, node);
-               unsigned i = 0;
-
-               for (i=0; i<channel->ses_left.streams_count; i++) {
-                       zrtp_test_stream_t *stream = &channel->ses_left.streams[i];
-                       if (stream->ssrc == ssrc) {
-                               is_found = 1;
-                               result = &channel->ses_right.streams[i];
-                               break;
-                       }
-               }
-               
-               for (i=0; i<channel->ses_right.streams_count; i++) {
-                       zrtp_test_stream_t *stream = &channel->ses_right.streams[i];
-                       if (stream->ssrc == ssrc) {
-                               is_found = 1;
-                               result = &channel->ses_left.streams[i];
-                               break;
-                       }
-               }
-               
-               if (is_found) {
-                       break;
-               }
-       }
-       zrtp_mutex_unlock(test_global.channels_protector);
-       
-       return (is_found) ? result : NULL;
-}
diff --git a/libs/libzrtp/test/pc/zrtp_test_core.h b/libs/libzrtp/test/pc/zrtp_test_core.h
deleted file mode 100644 (file)
index 4a99fac..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * libZRTP SDK library, implements the ZRTP secure VoIP protocol.
- * Copyright (c) 2006-2009 Philip R. Zimmermann.  All rights reserved.
- * Contact: http://philzimmermann.com
- * For licensing and other legal details, see the file zrtp_legal.c.
- * 
- * Viktor Krykun <v.krikun at zfoneproject.com> 
- */
-
-#ifndef __ZRTP_TEST_CORE_H__
-#define __ZRTP_TEST_CORE_H__
-
-#include "zrtp.h"
-
-extern zrtp_global_t* zrtp_global;
-
-typedef uint32_t               zrtp_test_channel_id_t;
-
-typedef struct zrtp_test_channel_config
-{
-       unsigned                        streams_count;
-       unsigned char           is_autosecure;
-       unsigned char           is_preshared;
-} zrtp_test_channel_config_t;
-
-void zrtp_test_crypto(zrtp_global_t* zrtp);
-
-int zrtp_test_zrtp_init();
-int zrtp_test_zrtp_down();
-
-int zrtp_test_channel_create( const zrtp_test_channel_config_t* config,
-                                                         zrtp_test_channel_id_t* chan_id);
-int zrtp_test_channel_delete(zrtp_test_channel_id_t chan_id);
-int zrtp_test_channel_start(zrtp_test_channel_id_t chan_id);
-int zrtp_test_channel_secure(zrtp_test_channel_id_t chan_id);
-int zrtp_test_channel_clear(zrtp_test_channel_id_t chan_id);
-
-#endif /*__ZRTP_TEST_CORE_H__*/
diff --git a/libs/libzrtp/test/pc/zrtp_test_ui.c b/libs/libzrtp/test/pc/zrtp_test_ui.c
deleted file mode 100644 (file)
index bc1d6e2..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * libZRTP SDK library, implements the ZRTP secure VoIP protocol.
- * Copyright (c) 2006-2009 Philip R. Zimmermann.  All rights reserved.
- * Contact: http://philzimmermann.com
- * For licensing and other legal details, see the file zrtp_legal.c.
- * 
- * Viktor Krykun <v.krikun at zfoneproject.com> 
- */
-
-#include "zrtp_test_core.h"
-
-#ifndef ZRTP_TEST_ENABLE_CRYPTO_SELFTESTS
-#define ZRTP_TEST_ENABLE_CRYPTO_SELFTESTS 0
-#endif
-
-static zrtp_test_channel_id_t tmp_id;
-
-void do_create()
-{
-       zrtp_test_channel_config_t      config;
-       int status = 0;
-       
-       config.is_autosecure    = 1;
-       config.is_preshared             = 0;
-       config.streams_count    = 1;
-       
-       status  = zrtp_test_channel_create(&config, &tmp_id);
-}
-
-void do_delete()
-{
-       zrtp_test_channel_delete(tmp_id);
-}
-
-void do_quit()
-{
-       zrtp_test_zrtp_down();
-}
-
-int main()
-{
-       int status;
-       
-       status = zrtp_test_zrtp_init();
-       if (0 != status) {
-               return status;
-       }
-#if (ZRTP_TEST_ENABLE_CRYPTO_SELFTESTS == 1)
-       zrtp_test_crypto(zrtp_global);
-#endif
-       
-       {
-               zrtp_test_channel_id_t id;
-               zrtp_test_channel_config_t sconfig;
-               
-               sconfig.is_autosecure = 0;
-               sconfig.is_preshared  = 0;
-               sconfig.streams_count = 1;
-               
-               status = zrtp_test_channel_create(&sconfig, &id);
-               
-               if (0 == status) {
-                       zrtp_test_channel_start(id);
-               }
-       }
-       
-       while (1) {
-               zrtp_sleep(1000);
-       }
-       
-       
-       do_quit();
-       
-       return 0;
-}
similarity index 85%
rename from libs/libzrtp/test/pc/zrtp_test_queue.c
rename to libs/libzrtp/test/queue.c
index 488f36f3c389098467e3a885f5f9ae168fa2ac4f..4b0d9b819450b12335ed0a98e5fd522992923101 100644 (file)
@@ -8,10 +8,9 @@
  */
 
 #include "zrtp.h"
-#include "zrtp_test_queue.h"
+#include "queue.h"
 
-struct zrtp_queue
-{
+struct zrtp_queue {
        zrtp_sem_t*                     size_sem;
        zrtp_sem_t*                     main_sem;
        zrtp_mutex_t*           mutex;    
@@ -19,9 +18,9 @@ struct zrtp_queue
        uint32_t                        size;
 };
 
-/*----------------------------------------------------------------------------*/
-zrtp_status_t zrtp_test_queue_create(zrtp_queue_t** queue)
-{
+
+zrtp_status_t zrtp_test_queue_create(zrtp_queue_t** queue) {
+       
        zrtp_status_t s = zrtp_status_fail;
        zrtp_queue_t* new_queue = (zrtp_queue_t*) zrtp_sys_alloc(sizeof(zrtp_queue_t));
        if (! new_queue) {
@@ -67,8 +66,7 @@ zrtp_status_t zrtp_test_queue_create(zrtp_queue_t** queue)
     return s;  
 }
 
-void zrtp_test_queue_destroy(zrtp_queue_t* queue)
-{
+void zrtp_test_queue_destroy(zrtp_queue_t* queue) {
        if (queue->size_sem) {
                zrtp_sem_destroy(queue->size_sem);
        }
@@ -80,9 +78,8 @@ void zrtp_test_queue_destroy(zrtp_queue_t* queue)
        }
 }
 
-/*----------------------------------------------------------------------------*/
-void zrtp_test_queue_push(zrtp_queue_t* queue, zrtp_queue_elem_t* elem)
-{
+
+void zrtp_test_queue_push(zrtp_queue_t* queue, zrtp_queue_elem_t* elem) {
        zrtp_sem_wait(queue->size_sem);
        
        zrtp_mutex_lock(queue->mutex);
@@ -93,8 +90,7 @@ void zrtp_test_queue_push(zrtp_queue_t* queue, zrtp_queue_elem_t* elem)
        zrtp_sem_post(queue->main_sem);
 }
 
-zrtp_queue_elem_t* zrtp_test_queue_pop(zrtp_queue_t* queue)
-{
+zrtp_queue_elem_t* zrtp_test_queue_pop(zrtp_queue_t* queue) {
        zrtp_queue_elem_t* res = NULL;
        zrtp_sem_wait(queue->main_sem);
        
similarity index 96%
rename from libs/libzrtp/test/pc/zrtp_test_queue.h
rename to libs/libzrtp/test/queue.h
index 17ecec80af9f45e1d18ff4db439e0f323cc0b5d8..6a0cbe2bfed8f948d106ed7b45fc1595ac9d7fce 100644 (file)
@@ -14,8 +14,7 @@
 
 #define ZRTP_QUEUE_SIZE 2000
 
-typedef struct zrtp_queue_elem
-{
+typedef struct zrtp_queue_elem {
     char               data[1500];
     uint32_t   size;
     mlist_t            _mlist;
diff --git a/libs/libzrtp/test/sasrelay_test.c b/libs/libzrtp/test/sasrelay_test.c
new file mode 100644 (file)
index 0000000..5148c6a
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * libZRTP SDK library, implements the ZRTP secure VoIP protocol.
+ * Copyright (c) 2006-2009 Philip R. Zimmermann.  All rights reserved.
+ * Contact: http://philzimmermann.com
+ * For licensing and other legal details, see the file zrtp_legal.c.
+ *
+ * Viktor Krykun <v.krikun at zfoneproject.com>
+ */
+
+#include <setjmp.h>            /*chmockery dependency*/
+#include <stdio.h>             /*chmockery dependency*/
+#include <unistd.h>    /*for usleep*/
+
+#include "cmockery/cmockery.h"
+#include "test_engine.h"
+
+#include "enroll_test_helpers.c"
+
+static void enrollment_test() {
+       zrtp_status_t s;
+
+       zrtp_test_channel_info_t a2pbx_channel_info, b2pbx_channel_info;
+       zrtp_test_session_cfg_t session_config, session_config_enroll;
+       zrtp_test_session_config_defaults(&session_config);
+       zrtp_test_session_config_defaults(&session_config_enroll);
+
+       session_config_enroll.is_enrollment = 1;
+
+       /**************************************************************************
+        * Enroll both Alice and Bob to PBX
+        */
+       prepare_alice_pbx_bob_setup(&session_config, &session_config, &session_config_enroll, &session_config_enroll);
+
+       /* Everything is ready. Let's start the stream and give it few seconds to switch secure. */
+       s = zrtp_test_channel_start(g_alice2pbx_channel);
+       assert_int_equal(zrtp_status_ok, s);
+       s = zrtp_test_channel_start(g_bob2pbx_channel);
+       assert_int_equal(zrtp_status_ok, s);
+
+       int i = 30;
+       for (; i>0; i--) {
+               usleep(100*1000);
+       }
+
+       s = zrtp_test_channel_get(g_alice2pbx_channel, &a2pbx_channel_info);
+       assert_int_equal(zrtp_status_ok, s);
+       s = zrtp_test_channel_get(g_bob2pbx_channel, &b2pbx_channel_info);
+       assert_int_equal(zrtp_status_ok, s);
+
+       /* Both, Alice and Bob should switch secure and ready for enrollment */
+       assert_true(a2pbx_channel_info.is_secure);
+       assert_true(b2pbx_channel_info.is_secure);
+
+       /* Confirm enrollment for both, Alice and Bob */
+       zrtp_test_id_t alice2pbx_stream = zrtp_test_session_get_stream_by_idx(g_alice_sid, 0);
+       zrtp_test_id_t bob2pbx_stream = zrtp_test_session_get_stream_by_idx(g_bob_sid, 0);
+
+       s = zrtp_register_with_trusted_mitm(zrtp_stream_for_test_stream(alice2pbx_stream));
+       assert_int_equal(zrtp_status_ok, s);
+       s = zrtp_register_with_trusted_mitm(zrtp_stream_for_test_stream(bob2pbx_stream));
+       assert_int_equal(zrtp_status_ok, s);
+
+       /* Clean-up */
+       cleanup_alice_pbx_bob_setup();
+
+       /**************************************************************************
+        * Now, when we have two enrolled parties, make one more call and initiate
+        * SAS Relay at the PBX side. Both endpoints should received SASRelay, but
+        * just one should get ZRTP_EVENT_LOCAL_SAS_UPDATED event.
+        */
+
+       prepare_alice_pbx_bob_setup(&session_config, &session_config, &session_config, &session_config);
+
+       /* Everything is ready. Let's start the stream and give it few seconds to switch secure. */
+       s = zrtp_test_channel_start(g_alice2pbx_channel);
+       assert_int_equal(zrtp_status_ok, s);
+       s = zrtp_test_channel_start(g_bob2pbx_channel);
+       assert_int_equal(zrtp_status_ok, s);
+
+       i = 30;
+       for (; i>0; i--) {
+               usleep(100*1000);
+       }
+
+       s = zrtp_test_channel_get(g_alice2pbx_channel, &a2pbx_channel_info);
+       assert_int_equal(zrtp_status_ok, s);
+       s = zrtp_test_channel_get(g_bob2pbx_channel, &b2pbx_channel_info);
+       assert_int_equal(zrtp_status_ok, s);
+
+       /* Both, Alice and Bob should switch secure */
+       assert_true(a2pbx_channel_info.is_secure);
+       assert_true(b2pbx_channel_info.is_secure);
+
+       zrtp_test_id_t pbx2alice_stream = zrtp_test_session_get_stream_by_idx(g_pbxa_sid, 0);
+       zrtp_test_id_t pbx2bob_stream = zrtp_test_session_get_stream_by_idx(g_pbxb_sid, 0);
+       alice2pbx_stream = zrtp_test_session_get_stream_by_idx(g_alice_sid, 0);
+       bob2pbx_stream = zrtp_test_session_get_stream_by_idx(g_bob_sid, 0);
+
+       /* Resolve MiTM call! */
+       s = zrtp_resolve_mitm_call(zrtp_stream_for_test_stream(pbx2alice_stream),
+                                                          zrtp_stream_for_test_stream(pbx2bob_stream));
+
+       i = 20;
+       for (; i>0; i--) {
+               usleep(100*1000);
+       }
+
+       /* Alice and Bob should receive Enrollment notification */
+       unsigned sas_update1 = zrtp_stream_did_event_receive(alice2pbx_stream, ZRTP_EVENT_LOCAL_SAS_UPDATED);
+       unsigned sas_update2 = zrtp_stream_did_event_receive(bob2pbx_stream, ZRTP_EVENT_LOCAL_SAS_UPDATED);
+       assert_true(sas_update1 ^ sas_update2);
+
+       /* Clean-up */
+       cleanup_alice_pbx_bob_setup();
+}
+
+int main(void) {
+       const UnitTest tests[] = {
+               unit_test_setup_teardown(enrollment_test, pbx_setup, pbx_teardown),
+       };
+
+       return run_tests(tests);
+}
diff --git a/libs/libzrtp/test/test_engine.c b/libs/libzrtp/test/test_engine.c
new file mode 100644 (file)
index 0000000..3b40985
--- /dev/null
@@ -0,0 +1,871 @@
+/*
+ * libZRTP SDK library, implements the ZRTP secure VoIP protocol.
+ * Copyright (c) 2006-2009 Philip R. Zimmermann.  All rights reserved.
+ * Contact: http://philzimmermann.com
+ * For licensing and other legal details, see the file zrtp_legal.c.
+ *
+ * Viktor Krykun <v.krikun at zfoneproject.com>
+ */
+
+#include <stdio.h>     /* for sprintf(), remove() */
+#include <string.h>    /* for string operations */
+
+#include "test_engine.h"
+#include "queue.h"
+
+#define _ZTU_ "test engine"
+
+#define K_ZRTP_TEST_MAX_ENDPOINTS 10
+#define K_ZRTP_TEST_MAX_SESSIONS_PER_ENDPOINT 100
+#define K_ZRTP_TEST_MAX_CHANNELS (K_ZRTP_TEST_MAX_ENDPOINTS * K_ZRTP_TEST_MAX_ENDPOINTS * ZRTP_MAX_STREAMS_PER_SESSION)
+
+#define K_ZRTP_TEST_PROCESSORS_COUNT 2
+#define K_ZRTP_TEST_RTP_RATE           200
+
+extern uint8_t hash_word_list_odd[256][12];
+extern uint8_t hash_word_list_even[256][10];
+
+typedef struct {
+       zrtp_test_id_t          id;
+       zrtp_test_id_t          session_id;
+       zrtp_test_id_t          channel_id;
+       zrtp_test_id_t          endpoint_id;
+       zrtp_stream_t           *zrtp;
+       uint16_t                        seq;
+       zrtp_queue_t            *input;
+       zrtp_queue_t            *output;
+       unsigned                        zrtp_events_queueu[128];
+       unsigned                        zrtp_events_count;
+} zrtp_test_stream_t;
+
+typedef struct {
+       zrtp_test_id_t id;
+       zrtp_test_id_t endpoint_id;
+       zrtp_test_session_cfg_t cfg;
+       zrtp_session_t *zrtp;
+       zrtp_test_stream_t streams[ZRTP_MAX_STREAMS_PER_SESSION];
+       unsigned streams_count;
+} zrtp_test_session_t;
+
+typedef struct {
+       zrtp_test_id_t id;
+       char name[ZRTP_TEST_STR_LEN];
+       zrtp_zid_t zid;
+       zrtp_test_endpoint_cfg_t cfg;
+       zrtp_test_session_t sessions[K_ZRTP_TEST_MAX_SESSIONS_PER_ENDPOINT];
+       unsigned sessions_count;
+       zrtp_global_t *zrtp;
+       unsigned is_running;
+       zrtp_queue_t *input_queue;
+} zrtp_endpoint_t;
+
+
+typedef struct {
+       zrtp_test_id_t          id;
+       zrtp_test_stream_t      *left;
+       zrtp_test_stream_t      *right;
+       unsigned                        is_attached;
+       unsigned                        is_secure;
+} zrtp_test_channel_t;
+
+typedef struct zrtp_test_packet {
+       uint32_t                        is_rtp;                 /*! Defines is packet RTP or RTCP */
+       uint32_t                        length;                 /*! Packet Length in bytes */
+       char                            body[1024];             /*! Packet body */
+} zrtp_test_packet_t;
+
+
+static zrtp_endpoint_t g_test_endpoints[K_ZRTP_TEST_MAX_ENDPOINTS];
+static unsigned g_test_endpoints_count = 0;
+
+static zrtp_test_channel_t g_test_channels[K_ZRTP_TEST_MAX_CHANNELS];
+static unsigned g_test_channels_count = 0;
+
+static int g_endpoints_counter = 7;
+static int g_channels_counter = 7;
+static int g_sessions_counter = 7;
+static int g_streams_counter = 7;
+
+
+zrtp_endpoint_t *zrtp_test_endpoint_by_id(zrtp_test_id_t id);
+zrtp_test_stream_t *zrtp_test_stream_by_id(zrtp_test_id_t id);
+zrtp_test_stream_t *zrtp_test_stream_by_peerid(zrtp_test_id_t id);
+zrtp_test_session_t *zrtp_test_session_by_id(zrtp_test_id_t id);
+zrtp_test_channel_t *zrtp_test_channel_by_id(zrtp_test_id_t id);
+
+
+/******************************************************************************
+ * libzrtp interface implementation
+ */
+
+static void on_zrtp_event(zrtp_stream_t *ctx, zrtp_protocol_event_t event) {
+       zrtp_test_id_t *stream_id = zrtp_stream_get_userdata(ctx);
+       zrtp_test_stream_t *stream = zrtp_test_stream_by_id(*stream_id);
+
+       stream->zrtp_events_queueu[stream->zrtp_events_count++] = event;
+}
+
+
+static void on_zrtp_secure(zrtp_stream_t *ctx) {
+       zrtp_test_id_t *stream_id = zrtp_stream_get_userdata(ctx);
+       zrtp_test_stream_t *stream = zrtp_test_stream_by_id(*stream_id);
+       zrtp_test_channel_t *channel = zrtp_test_channel_by_id(stream->channel_id);
+       zrtp_test_stream_t *remote_stream = (channel->left == stream) ? channel->right : channel->left;
+
+       if (stream->zrtp->state == ZRTP_STATE_SECURE &&
+               remote_stream->zrtp->state == ZRTP_STATE_SECURE) {
+               channel->is_secure = 1;
+       }
+
+}
+
+static int on_send_packet(const zrtp_stream_t* ctx, char* message, unsigned int length) {
+       zrtp_queue_elem_t* elem = zrtp_sys_alloc(sizeof(zrtp_queue_elem_t));
+       if (elem) {
+               zrtp_test_packet_t* packet = (zrtp_test_packet_t*) elem->data;
+               elem->size = length;
+
+               packet->is_rtp = 1;
+               packet->length = length;
+               zrtp_memcpy(packet->body, message, length);
+
+               zrtp_test_id_t *stream_id = zrtp_stream_get_userdata(ctx);
+               zrtp_test_stream_t *stream = zrtp_test_stream_by_id(*stream_id);
+               if (stream) {
+                       printf("trace>>> PUSH from stream ID=%u\n", stream->id);
+                       zrtp_test_queue_push(stream->output, elem);
+                       return zrtp_status_ok;
+               } else {
+                       return zrtp_status_fail;
+               }
+       } else {
+               return zrtp_status_alloc_fail;
+       }
+}
+
+
+/******************************************************************************
+ * Processing Loop
+ */
+
+static zrtp_test_stream_t *get_stream_to_process_(zrtp_endpoint_t *endpoint) {
+       zrtp_test_id_t all_streams[K_ZRTP_TEST_MAX_SESSIONS_PER_ENDPOINT*ZRTP_MAX_STREAMS_PER_SESSION];
+       unsigned streams_count = 0;
+       unsigned i, j;
+
+       for (i=0; i<endpoint->sessions_count; i++) {
+               for (j=0; j<endpoint->sessions[i].streams_count; j++) {
+                       zrtp_test_stream_t *stream = &endpoint->sessions[i].streams[j];
+                       if (stream->input && stream->output)
+                               all_streams[streams_count++] = stream->id;
+               }
+       }
+
+       if (0 == streams_count)
+               return NULL;
+
+       zrtp_randstr(endpoint->zrtp, (unsigned char*)&i, sizeof(i));
+       j = (unsigned)i;
+       j = j % streams_count;
+
+       printf("trace>>> CHOOSE stream Endpoint=%u IDX=%u ID=%u\n", endpoint->id,  j, all_streams[j]);
+       return zrtp_test_stream_by_id(all_streams[j]);
+
+
+//     unsigned is_found = 0;
+//     zrtp_test_id_t result, left;
+//     for (i=0; i<streams_count; i++) {
+//             result = all_streams[i];
+//             if (result > stream_id) {
+//                     is_found = 1;
+//                     break;
+//             } else {
+//                     left = result;
+//             }
+//     }
+//
+//     printf("TRACE>>> choose stream ID=%u\n", is_found ? result : left);
+//     return zrtp_test_stream_by_id(is_found ? result : left);
+}
+
+
+#if   (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE)
+DWORD WINAPI process_incoming(void *param)
+#else
+void *process_incoming(void *param)
+#endif
+{
+       zrtp_endpoint_t *the_endpoint = (zrtp_endpoint_t *)param;
+
+       while (the_endpoint->is_running) {
+               zrtp_test_packet_t* packet = NULL;
+               zrtp_queue_elem_t* elem = NULL;
+               zrtp_status_t s = zrtp_status_fail;
+               zrtp_test_stream_t *stream;
+               int is_protocol = 0;
+
+               // TODO: use peak to not to block processing if queue for this stream is empty
+               elem = zrtp_test_queue_pop(the_endpoint->input_queue);
+               if (!elem || elem->size <= 0) {
+                       if (elem) zrtp_sys_free(elem);
+                       break;
+               }
+
+               packet = (zrtp_test_packet_t*) elem->data;
+               zrtp_test_id_t stream_id;
+               {
+                       if (packet->is_rtp) {
+                               ZRTP_UNALIGNED(zrtp_rtp_hdr_t) *rtp_hdr = (zrtp_rtp_hdr_t*)packet->body;
+                               stream_id = zrtp_ntoh32(rtp_hdr->ssrc); /* remember, we use stream Id as it's RTP SSRC */
+                       } else {
+                               ZRTP_UNALIGNED(zrtp_rtcp_hdr_t) *rtcp_hdr = (zrtp_rtcp_hdr_t*)packet->body;
+                               stream_id = zrtp_ntoh32(rtcp_hdr->ssrc); /* remember, we use stream Id as it's RTP SSRC */
+                       }
+                       stream = zrtp_test_stream_by_peerid(stream_id);
+               }
+
+               /*
+                * Process incoming packet by libzrtp. Is this a RTP media packet - copy it to the buffer
+                * to print out later.
+                */
+               if (packet->is_rtp) {
+                       s = zrtp_process_srtp(stream->zrtp, packet->body, &packet->length);
+               } else {
+                       s = zrtp_process_srtcp(stream->zrtp, packet->body, &packet->length);
+               }
+
+               if (!is_protocol) {
+                       char *body;
+                       if (packet->is_rtp) {
+                               body = packet->body + sizeof(zrtp_rtp_hdr_t);
+                               body[packet->length - sizeof(zrtp_rtp_hdr_t)] = 0;
+                       } else {
+                               body = packet->body + sizeof(zrtp_rtcp_hdr_t);
+                               body[packet->length - sizeof(zrtp_rtcp_hdr_t)] = 0;
+                       }
+
+                       switch (s)
+                       {
+                       case zrtp_status_ok: {
+                               ZRTP_LOG(1, (_ZTU_,"Incoming: (%s) [%p:ssrc=%u] OK. <%s> decrypted %d bytes.\n",
+                                               zrtp_log_state2str(stream->zrtp->state), stream->zrtp,  stream->id, body, packet->length));
+                       } break;
+
+                       case zrtp_status_drop: {
+                               ZRTP_LOG(1, (_ZTU_,"Incoming: (%s) [%p:ssrc=%u] DROPPED. <%s>\n",
+                                               zrtp_log_state2str(stream->zrtp->state), stream->zrtp, stream->id, body));
+                       } break;
+
+                       case zrtp_status_fail: {
+                               ZRTP_LOG(1, (_ZTU_,"Incoming: (%s) [%p:ssrc=%u] DECRYPT FAILED. <%s>\n",
+                                               zrtp_log_state2str(stream->zrtp->state), stream->zrtp, stream->id, body));
+                       } break;
+
+                       default:
+                               break;
+                       }
+               }
+
+               zrtp_sys_free(elem);
+
+               /*
+                * When zrtp_stream is in the pending clear state and other side wants to send plain
+                * traffic. We have to call zrtp_clear_stream().
+                */
+               if (stream->zrtp->state == ZRTP_STATE_PENDINGCLEAR) {
+                       zrtp_stream_clear(stream->zrtp);
+               }
+       }
+#if   (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE)
+       return 0;
+#else
+       return NULL;
+#endif
+}
+
+#if   (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE)
+DWORD WINAPI process_outgoing(void *param)
+#else
+void *process_outgoing(void *param)
+#endif
+{
+       unsigned packets_counter = 0;
+       zrtp_endpoint_t *the_endpoint = (zrtp_endpoint_t *)param;
+
+       while (the_endpoint->is_running) {
+               zrtp_test_stream_t* stream = NULL;
+               unsigned i;
+
+               zrtp_status_t s = zrtp_status_fail;
+               zrtp_test_packet_t* packet;
+               zrtp_queue_elem_t* elem;
+               char* word = NULL;
+
+               zrtp_sleep(K_ZRTP_TEST_RTP_RATE);
+
+               /* Get random channel to operate with and select random peer */
+               stream = get_stream_to_process_(the_endpoint);
+               if (!stream) {
+                       continue;
+               }
+
+               elem = zrtp_sys_alloc(sizeof(zrtp_queue_elem_t));
+               if (!elem) {
+                       break;
+               }
+               packet = (zrtp_test_packet_t*) elem->data;
+               packet->is_rtp = (packets_counter++ % 20); /* Every 20-th packet is RTCP */
+
+               /*
+                * Construct RTP/RTCP Packet
+                */
+               if (packet->is_rtp)
+               {
+                       ZRTP_UNALIGNED(zrtp_rtp_hdr_t) *rtp_hdr = (zrtp_rtp_hdr_t*)packet->body;
+
+                       /* Fill RTP Header according to the specification */
+                       zrtp_memset(rtp_hdr, 0, sizeof(zrtp_rtp_hdr_t));
+                       rtp_hdr->version = 2;                   /* Current RTP version 2 */
+                       rtp_hdr->pt = 0;                                /* PCMU padding type */
+                       rtp_hdr->ssrc = zrtp_hton32(stream->id);                /* Use stream Identifier as it's SSRC */
+                       if (stream->seq >= 0xFFFF) {
+                               stream->seq = 0;
+                       }
+                       rtp_hdr->seq = zrtp_hton16(stream->seq++);
+                       rtp_hdr->ts = zrtp_hton32((uint32_t)(zrtp_time_now()/1000));
+
+                       /* Get RTP body from PGP words lists */
+                       word = (char*)(i ? hash_word_list_odd[packets_counter % 256] : hash_word_list_even[packets_counter % 256]);
+
+                       zrtp_memcpy(packet->body + sizeof(zrtp_rtp_hdr_t), word, (uint32_t)strlen(word));
+                       packet->length = sizeof(zrtp_rtp_hdr_t) + (uint32_t)strlen(word);
+
+                       /* Process RTP media with libzrtp */
+                       s = zrtp_process_rtp(stream->zrtp, packet->body, &packet->length);
+               }
+               else {
+                       ZRTP_UNALIGNED(zrtp_rtcp_hdr_t) *rtcp_hdr = (zrtp_rtcp_hdr_t*)packet->body;
+
+                       /* Fill RTCP Header according to the specification */
+                       rtcp_hdr->rc = 0;
+                       rtcp_hdr->version = 2;
+                       rtcp_hdr->ssrc = stream->id;
+
+                       /* Get RTP body from PGP words lists. Put RTCP marker at the beginning */
+                       zrtp_memcpy(packet->body + sizeof(zrtp_rtcp_hdr_t), "RTCP", 4);
+                       word = (char*)( i ? hash_word_list_odd[packets_counter % 256] : hash_word_list_even[packets_counter % 256]);
+
+                       zrtp_memcpy(packet->body + sizeof(zrtp_rtcp_hdr_t) + 4, word, (uint32_t)strlen(word));
+                       packet->length = sizeof(zrtp_rtcp_hdr_t) + (uint32_t)strlen(word) + 4;
+                       /* RTCP packets sould be 32 byes aligned */
+                       packet->length += (packet->length % 4) ? (4 - packet->length % 4) : 0;
+
+                       /* Process RTCP control with libzrtp */
+                       s = zrtp_process_rtcp(stream->zrtp, packet->body, &packet->length);
+               }
+
+               elem->size = packet->length;
+
+               /* Handle zrtp_process_xxx() instructions */
+               switch (s) {
+               /* Put the packet to the queue ==> send packet to the other side pear */
+               case zrtp_status_ok: {
+                       ZRTP_LOG(3, (_ZTU_,"Outgoing: (%s) [%p:ssrc=%u] OK. <%s%s> encrypted %d bytes.\n",
+                                       zrtp_log_state2str(stream->zrtp->state), stream->zrtp, stream->id, packet->is_rtp ? "" : "RTCP", word, packet->length));
+                       zrtp_test_queue_push(stream->output, elem);
+               } break;
+
+               case zrtp_status_drop: {
+                       ZRTP_LOG(1, (_ZTU_,"Outgoing: (%s) [%p:ssrc=%u] DROPPED.\n",
+                                       zrtp_log_state2str(stream->zrtp->state), stream->zrtp, stream->id));
+               } break;
+
+               case zrtp_status_fail: {
+                       ZRTP_LOG(1, (_ZTU_,"Outgoing: (%s) [%p:ssrc=%u] ENCRYPT FAILED.\n",
+                                       zrtp_log_state2str(stream->zrtp->state), stream->zrtp, stream->id));
+               }       break;
+
+               default:
+                       break;
+               }
+
+               if (zrtp_status_ok != s) {
+                       zrtp_sys_free(packet);
+               }
+       }
+#if   (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE)
+       return 0;
+#else
+       return NULL;
+#endif
+}
+
+
+/******************************************************************************
+ * Test Engine Public API
+ */
+
+void zrtp_test_endpoint_config_defaults(zrtp_test_endpoint_cfg_t* cfg) {
+
+       zrtp_memset(cfg, 0, sizeof(zrtp_test_endpoint_cfg_t));
+
+       cfg->generate_traffic = 0;
+
+       /* It's always a good idea to start with default values */
+       zrtp_config_defaults(&cfg->zrtp);
+
+       /* Set ZRTP client id */
+       strcpy(cfg->zrtp.client_id, "zrtp-test-engine");
+
+       cfg->zrtp.is_mitm = 0;
+       cfg->zrtp.lic_mode = ZRTP_LICENSE_MODE_ACTIVE;
+
+       cfg->zrtp.cb.event_cb.on_zrtp_secure                    = &on_zrtp_secure;
+       cfg->zrtp.cb.event_cb.on_zrtp_security_event    = &on_zrtp_event;
+       cfg->zrtp.cb.event_cb.on_zrtp_protocol_event    = &on_zrtp_event;
+       cfg->zrtp.cb.misc_cb.on_send_packet                             = &on_send_packet;
+}
+
+zrtp_status_t zrtp_test_endpoint_create(zrtp_test_endpoint_cfg_t* cfg,
+                                                                               const char *name,
+                                                                               zrtp_test_id_t* id) {
+       zrtp_status_t s;
+       unsigned i;
+       char cache_file_path[ZRTP_TEST_STR_LEN];
+       zrtp_endpoint_t *new_endpoint;
+
+       if (g_test_endpoints_count >= K_ZRTP_TEST_MAX_ENDPOINTS)
+               return zrtp_status_alloc_fail;
+
+       new_endpoint = &g_test_endpoints[g_test_endpoints_count++];
+       zrtp_memset(new_endpoint, 0, sizeof(zrtp_endpoint_t));
+
+       /* Copy configuration, we will use it later to clean up after ourselves */
+       zrtp_memcpy(&new_endpoint->cfg, cfg, sizeof(zrtp_test_endpoint_cfg_t));
+
+       /* Remember endpoint name */
+       strcpy(new_endpoint->name, name);
+
+       new_endpoint->id = g_endpoints_counter++;
+
+       /* Adjust cache file path so each endpoint will use it's own file. */
+       sprintf(cache_file_path, "./%s_cache.dat", name);
+       zrtp_zstrcpyc(ZSTR_GV(new_endpoint->cfg.zrtp.def_cache_path), cache_file_path);
+
+       /* Initialize libzrtp engine for this endpoint */
+       s = zrtp_init(&new_endpoint->cfg.zrtp, &new_endpoint->zrtp);
+       if (zrtp_status_ok == s) {
+               *id = new_endpoint->id;
+
+               /* Generate random ZID */
+               zrtp_randstr(new_endpoint->zrtp, new_endpoint->zid, sizeof(new_endpoint->zid));
+       }
+
+       /* Create Input queue*/
+       s = zrtp_test_queue_create(&new_endpoint->input_queue);
+       if (zrtp_status_ok != s) {
+               return s;
+       }
+
+       /* Start processing loop */
+       new_endpoint->is_running = 1;
+
+       for (i = 0; i<K_ZRTP_TEST_PROCESSORS_COUNT; i++) {
+               if (0 != zrtp_thread_create(process_incoming, new_endpoint)) {
+                       return zrtp_status_fail;
+               }
+
+               if (cfg->generate_traffic) {
+                       if (0 != zrtp_thread_create(process_outgoing, new_endpoint)) {
+                               return zrtp_status_fail;
+                       }
+               }
+       }
+
+       return s;
+}
+
+zrtp_status_t zrtp_test_endpoint_destroy(zrtp_test_id_t id) {
+       unsigned i;
+       zrtp_status_t s = zrtp_status_ok;
+       zrtp_endpoint_t *endpoint = zrtp_test_endpoint_by_id(id);
+
+       endpoint->is_running = 0;
+
+       if (endpoint->input_queue) {
+               /* Push faked element to the queue to unlock incoming threads */
+               for (i=0; i<K_ZRTP_TEST_PROCESSORS_COUNT; i++) {
+                       zrtp_queue_elem_t *elem = malloc(sizeof(zrtp_queue_elem_t));
+                       elem->size = 0;
+                       zrtp_test_queue_push(endpoint->input_queue, elem);
+               }
+               zrtp_sleep(0.5*1000);
+
+               zrtp_test_queue_destroy(endpoint->input_queue);
+       }
+
+       for (i=0; i<20; i++) zrtp_sleep(100);
+
+       if (endpoint) {
+               /* Shut down libzrtp */
+               if (endpoint->zrtp)
+                       s = zrtp_down(endpoint->zrtp);
+
+               /* Clean-up ZRTP cache after ourselves */
+               remove(endpoint->cfg.zrtp.def_cache_path.buffer);
+       } else {
+               s = zrtp_status_fail;
+       }
+
+       return s;
+}
+
+zrtp_status_t zrtp_test_stream_get(zrtp_test_id_t id,
+                                                                  zrtp_test_stream_info_t* info) {
+
+       zrtp_test_stream_t *stream = zrtp_test_stream_by_id(id);
+       if (stream) {
+               zrtp_status_t s;
+               zrtp_memset(info, 0, sizeof(zrtp_test_stream_info_t));
+
+               zrtp_memcpy(info->zrtp_events_queueu, stream->zrtp_events_queueu, sizeof(info->zrtp_events_queueu));
+               info->zrtp_events_count = stream->zrtp_events_count;
+
+               s = zrtp_stream_get(stream->zrtp, &info->zrtp);
+               return s;
+       } else {
+               return zrtp_status_bad_param;
+       }
+}
+
+void zrtp_test_session_config_defaults(zrtp_test_session_cfg_t* cfg) {
+       cfg->streams_count = 1;
+       cfg->role = ZRTP_SIGNALING_ROLE_UNKNOWN;
+       cfg->is_enrollment = 0;
+
+       zrtp_profile_defaults(&cfg->zrtp, NULL);
+}
+
+zrtp_status_t zrtp_test_session_create(zrtp_test_id_t endpoint_id,
+                                                                          zrtp_test_session_cfg_t* cfg,
+                                                                          zrtp_test_id_t* id) {
+       zrtp_status_t s;
+       unsigned i;
+       zrtp_test_session_t *the_session;
+       zrtp_endpoint_t *the_endpoint = zrtp_test_endpoint_by_id(endpoint_id);
+
+       if (!the_endpoint)
+               return zrtp_status_fail;
+
+       if (the_endpoint->sessions_count >= K_ZRTP_TEST_MAX_SESSIONS_PER_ENDPOINT)
+               return zrtp_status_fail;
+
+       the_session = &the_endpoint->sessions[the_endpoint->sessions_count++];
+
+       zrtp_memset(the_session, 0, sizeof(zrtp_test_session_t));
+
+       zrtp_memcpy(&the_session->cfg, cfg, sizeof(zrtp_test_session_cfg_t));
+
+       the_session->id = g_sessions_counter++;
+       the_session->endpoint_id = endpoint_id;
+
+       s = zrtp_session_init(the_endpoint->zrtp,
+                                                 &cfg->zrtp,
+                                                 the_endpoint->zid,
+                                                 cfg->role,
+                                                 &the_session->zrtp);
+
+       if (zrtp_status_ok == s) {
+
+               zrtp_session_set_userdata(the_session->zrtp, &the_session->id);
+
+               for (i=0; i<cfg->streams_count; i++) {
+                       zrtp_test_stream_t *the_stream = &the_session->streams[i];
+                       zrtp_memset(the_stream, 0, sizeof(zrtp_test_stream_t));
+
+                       the_stream->id = g_streams_counter++;
+                       the_stream->session_id = the_session->id;
+                       the_stream->endpoint_id = endpoint_id;
+
+                       s = zrtp_stream_attach(the_session->zrtp, &the_stream->zrtp);
+                       if (zrtp_status_ok == s) {
+                               zrtp_stream_set_userdata(the_stream->zrtp, &the_stream->id);
+                               the_session->streams_count++;
+                       } else {
+                               break;
+                       }
+               }
+       }
+
+       if (zrtp_status_ok == s) {
+               *id = the_session->id;
+       }
+
+       return s;
+}
+
+zrtp_status_t zrtp_test_session_destroy(zrtp_test_id_t id) {
+       zrtp_test_session_t *session = zrtp_test_session_by_id(id);
+       if (session) {
+               /* NOTE: we don't release session slots here due to nature of testing
+                * engine: test configuration constructed from scratch for every single test.
+                */
+               zrtp_session_down(session->zrtp);
+       }
+       return zrtp_status_ok;
+}
+
+zrtp_status_t zrtp_test_session_get(zrtp_test_id_t id, zrtp_test_session_info_t* info) {
+       zrtp_status_t s;
+       zrtp_test_session_t *session = zrtp_test_session_by_id(id);
+       if (session) {
+               s = zrtp_session_get(session->zrtp, &info->zrtp);
+               if (zrtp_status_ok == s) {
+                       unsigned i;
+                       for (i=0; i<session->streams_count; i++) {
+                               s = zrtp_test_stream_get(session->streams[i].id, &info->streams[i]);
+                               if (zrtp_status_ok != s)
+                                       break;
+                       }
+               }
+
+               return s;
+       } else {
+               return zrtp_status_bad_param;
+       }
+}
+
+zrtp_status_t zrtp_test_channel_create(zrtp_test_id_t left_id, zrtp_test_id_t right_id, zrtp_test_id_t* id) {
+       zrtp_test_channel_t *the_channel;
+       zrtp_test_stream_t *left = zrtp_test_stream_by_id(left_id);
+       zrtp_test_stream_t *right = zrtp_test_stream_by_id(right_id);
+
+       if (!left || !right)
+               return zrtp_status_bad_param;
+
+       if (g_test_channels_count >= K_ZRTP_TEST_MAX_CHANNELS)
+               return zrtp_status_bad_param;
+
+       zrtp_endpoint_t *left_endpoint = zrtp_test_endpoint_by_id(left->endpoint_id);
+       zrtp_endpoint_t *right_endpoint = zrtp_test_endpoint_by_id(right->endpoint_id);
+
+       the_channel = &g_test_channels[g_test_channels_count++];
+       zrtp_memset(the_channel, 0, sizeof(zrtp_test_channel_t));
+
+       the_channel->id = g_channels_counter++;
+       the_channel->left = left;
+       the_channel->right = right;
+
+       left->output = right_endpoint->input_queue;
+       left->input = left_endpoint->input_queue;
+       right->output = left_endpoint->input_queue;
+       right->input = right_endpoint->input_queue;
+
+       right->channel_id = the_channel->id;
+       left->channel_id = the_channel->id;
+
+       the_channel->is_attached = 1;
+
+       *id = the_channel->id;
+
+       return zrtp_status_ok;
+}
+
+zrtp_status_t zrtp_test_channel_create2(zrtp_test_id_t left_session,
+                                                                               zrtp_test_id_t right_session,
+                                                                               unsigned stream_idx,
+                                                                               zrtp_test_id_t *id) {
+       zrtp_test_session_t *left = zrtp_test_session_by_id(left_session);
+       zrtp_test_session_t *right = zrtp_test_session_by_id(right_session);
+
+       if (!left || !right)
+               return zrtp_status_bad_param;
+
+       if (left->streams_count <= stream_idx || right->streams_count <= stream_idx)
+               return zrtp_status_bad_param;
+
+       return zrtp_test_channel_create(left->streams[stream_idx].id, right->streams[stream_idx].id, id);
+}
+
+zrtp_status_t zrtp_test_channel_destroy(zrtp_test_id_t id) {
+       zrtp_test_channel_t *channel = zrtp_test_channel_by_id(id);
+       if (!channel)
+               return zrtp_status_bad_param;
+
+       return zrtp_status_ok;
+}
+
+zrtp_status_t zrtp_test_channel_start(zrtp_test_id_t id) {
+       zrtp_status_t s1, s2;
+       zrtp_test_channel_t *the_channel = zrtp_test_channel_by_id(id);
+       zrtp_test_session_t *the_session;
+
+       the_session = zrtp_test_session_by_id(the_channel->left->session_id);
+       if (the_session->cfg.is_enrollment)
+               s1 = zrtp_stream_registration_start(the_channel->left->zrtp, the_channel->left->id); /* use stream Id as ssrc */
+       else
+               s1 = zrtp_stream_start(the_channel->left->zrtp, the_channel->left->id); /* use stream Id as ssrc */
+       if (s1 == zrtp_status_ok) {
+               the_session = zrtp_test_session_by_id(the_channel->right->session_id);
+               if (the_session->cfg.is_enrollment)
+                       s2 = zrtp_stream_registration_start(the_channel->right->zrtp, the_channel->right->id);
+               else
+                       s2 = zrtp_stream_start(the_channel->right->zrtp, the_channel->right->id);
+       } else {
+               return s1;
+       }
+
+       return s2;
+}
+
+zrtp_status_t zrtp_test_channel_get(zrtp_test_id_t id,
+                                                                       zrtp_test_channel_info_t* info) {
+
+       zrtp_test_channel_t *channel = zrtp_test_channel_by_id(id);
+       if (channel) {
+               zrtp_status_t s;
+
+               zrtp_memset(info, 0, sizeof(zrtp_test_channel_info_t));
+
+               s = zrtp_test_stream_get(channel->left->id, &info->left);
+               if (zrtp_status_ok == s) {
+                       s = zrtp_test_stream_get(channel->right->id, &info->right);
+                       if (zrtp_status_ok == s) {
+                               info->is_secure = channel->is_secure;
+                       }
+               }
+
+               return s;
+       } else {
+               return zrtp_status_bad_param;
+       }
+}
+
+
+/******************************************************************************
+ * Helpers
+ */
+
+zrtp_endpoint_t *zrtp_test_endpoint_by_id(zrtp_test_id_t id) {
+       int i;
+
+       if (ZRTP_TEST_UNKNOWN_ID == id) return NULL;
+
+       for (i=0; i<g_test_endpoints_count; i++) {
+               if (g_test_endpoints[i].id == id) {
+                       return &g_test_endpoints[i];
+               }
+       }
+
+       return NULL;
+}
+
+zrtp_test_session_t *zrtp_test_session_by_id(zrtp_test_id_t id) {
+       int i, j;
+
+       if (ZRTP_TEST_UNKNOWN_ID == id) return NULL;
+
+       for (i=0; i<g_test_endpoints_count; i++) {
+               zrtp_endpoint_t *endpoint = &g_test_endpoints[i];
+               if (endpoint->id == ZRTP_TEST_UNKNOWN_ID)
+                       continue;
+
+               for (j=0; j<endpoint->sessions_count; j++) {
+                       if (endpoint->sessions[j].id == id) {
+                               return  &endpoint->sessions[j];
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+zrtp_test_stream_t *zrtp_test_stream_by_id(zrtp_test_id_t id) {
+       int i, j, k;
+
+       if (ZRTP_TEST_UNKNOWN_ID == id) return NULL;
+
+       for (i=0; i<g_test_endpoints_count; i++) {
+               zrtp_endpoint_t *endpoint = &g_test_endpoints[i];
+               if (endpoint->id == ZRTP_TEST_UNKNOWN_ID)
+                       continue;
+
+               for (j=0; j<endpoint->sessions_count; j++) {
+                       zrtp_test_session_t *session = &endpoint->sessions[j];
+                       if (session->id == ZRTP_TEST_UNKNOWN_ID)
+                               continue;
+
+                       for (k=0; k<session->streams_count; k++) {
+                               if (session->streams[k].id  == id) {
+                                       return &session->streams[k];
+                               }
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+zrtp_test_channel_t *zrtp_test_channel_by_id(zrtp_test_id_t id) {
+       int i;
+       zrtp_test_channel_t *channel = NULL;
+
+       if (ZRTP_TEST_UNKNOWN_ID == id) return NULL;
+
+       for (i=0; i<g_test_channels_count; i++) {
+               if (g_test_channels[i].id != ZRTP_TEST_UNKNOWN_ID && g_test_channels[i].id == id) {
+                       channel = &g_test_channels[i];
+                       break;
+               }
+       }
+
+       return channel;
+}
+
+zrtp_test_stream_t *zrtp_test_stream_by_peerid(zrtp_test_id_t id) {
+       int i;
+       if (ZRTP_TEST_UNKNOWN_ID == id) return NULL;
+
+       for (i=0; i<g_test_channels_count; i++) {
+               if (g_test_channels[i].id != ZRTP_TEST_UNKNOWN_ID) {
+                       if (g_test_channels[i].left->id == id)
+                               return g_test_channels[i].right;
+                       else if (g_test_channels[i].right->id == id)
+                               return g_test_channels[i].left;
+               }
+       }
+
+       return NULL;
+}
+
+zrtp_test_id_t zrtp_test_session_get_stream_by_idx(zrtp_test_id_t session_id, unsigned idx) {
+       zrtp_test_session_t *session = zrtp_test_session_by_id(session_id);
+       if (session && session->streams_count > idx) {
+               return session->streams[idx].id;
+       } else {
+               return ZRTP_TEST_UNKNOWN_ID;
+       }
+}
+
+zrtp_stream_t *zrtp_stream_for_test_stream(zrtp_test_id_t stream_id) {
+       zrtp_test_stream_t *stream = zrtp_test_stream_by_id(stream_id);
+       if (stream) {
+               return stream->zrtp;
+       } else {
+               return NULL;
+       }
+}
+
+unsigned zrtp_stream_did_event_receive(zrtp_test_id_t stream_id, unsigned event) {
+       unsigned i;
+       zrtp_test_stream_info_t stream_info;
+
+       zrtp_test_stream_get(stream_id, &stream_info);
+       for (i=0; i<stream_info.zrtp_events_count; i++) {
+               if (stream_info.zrtp_events_queueu[i] == event)
+                       break;
+       }
+
+       return (i != stream_info.zrtp_events_count);
+}
+
diff --git a/libs/libzrtp/test/test_engine.h b/libs/libzrtp/test/test_engine.h
new file mode 100644 (file)
index 0000000..a8493ae
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * libZRTP SDK library, implements the ZRTP secure VoIP protocol.
+ * Copyright (c) 2006-2009 Philip R. Zimmermann.  All rights reserved.
+ * Contact: http://philzimmermann.com
+ * For licensing and other legal details, see the file zrtp_legal.c.
+ *
+ * Viktor Krykun <v.krikun at zfoneproject.com>
+ */
+
+#include "zrtp.h"
+
+/** libzrtp test elements identifier */
+typedef uint32_t zrtp_test_id_t;
+
+/** Defines constant for unknown test element identifier */
+#define ZRTP_TEST_UNKNOWN_ID 0
+
+/** Default lengths for libzrtp test string buffers */
+#define ZRTP_TEST_STR_LEN 128
+
+/** libzrtp test endpoint configuration */
+typedef struct {
+       zrtp_config_t                   zrtp;                           /** libzrtp global configuration parameters */
+       unsigned                                generate_traffic;       /** switch On to emulate RTP/RTCP traffic generation. Off by default. */
+} zrtp_test_endpoint_cfg_t;
+
+/** ZRTP test session parameters*/
+typedef struct {
+       zrtp_profile_t                  zrtp;                           /** libzrtp session parameters */
+       unsigned                                streams_count;          /** number of zrtp streams to be attached to the session */
+       zrtp_signaling_role_t   role;                           /** signaling role, default is ZRTP_SIGNALING_ROLE_UNKNOWN */
+       unsigned                                is_enrollment;          /** true if enrollment session should be created */
+} zrtp_test_session_cfg_t;
+
+/** ZRTP test stream info */
+typedef struct {
+       zrtp_stream_info_t              zrtp;                           /** libzrtp stream info */
+       unsigned                                zrtp_events_queueu[128]; /** list of received zrtp events*/
+       unsigned                                zrtp_events_count;      /** number of received events */
+} zrtp_test_stream_info_t;
+
+/** ZRTP test session state snapshot */
+typedef struct {
+       zrtp_session_info_t     zrtp;                           /** libzrtp session info*/
+       zrtp_test_stream_info_t streams[ZRTP_MAX_STREAMS_PER_SESSION]; /** array of attached streams info */
+       unsigned                                streams_count;          /** number streams attached to the session */
+} zrtp_test_session_info_t;
+
+/** *ZRTP test channel state */
+typedef struct {
+       zrtp_test_stream_info_t left;                           /** one-leg zrtp stream */
+       zrtp_test_stream_info_t right;                          /** second-leg zrtp stream */
+       unsigned  char                  is_secure;                      /** enabled when both streams in the channel are secure */
+} zrtp_test_channel_info_t;
+
+
+/**
+ * Initialize zrtp test endpoint configuration with default values
+ * @param cfg  - endpoint config to initialize
+ */
+void zrtp_test_endpoint_config_defaults(zrtp_test_endpoint_cfg_t *cfg);
+
+/**
+ * ZRTP test endpoint constructor
+ * One endpoint is created, it starts processing threads and ready to emulate ZRTP exchange.
+ *
+ * @param cfg  - endpoint configuration
+ * @param name - endpoint name for debug purposes and cache naming, e.h "Alice", "Bob".
+ * @param id   - just created endpoint identifier will be placed here
+ *
+ * @return zrtp_status_ok on success or some of zrtp_status_t error codes on failure
+ */
+zrtp_status_t zrtp_test_endpoint_create(zrtp_test_endpoint_cfg_t *cfg,
+                                                                               const char *name,
+                                                                               zrtp_test_id_t *id);
+
+/**
+ * ZRTP test endpoint destructor
+ * zrtp_test_endpoint_destroy() stops processing threads and release all
+ * recurses allocated in zrtp_test_endpoint_create().
+ *
+ * @param id   - endpoint identifier
+ * @return zrtp_status_ok on success or some of zrtp_status_t error codes on failure
+ */
+zrtp_status_t zrtp_test_endpoint_destroy(zrtp_test_id_t id);
+
+/**
+ * Enables test session config with default values
+ * @param cfg  - session config for initialization
+ */
+void zrtp_test_session_config_defaults(zrtp_test_session_cfg_t *cfg);
+
+/**
+ * Create zrtp test session
+ *
+ * @param endpoint     - test endpoint creating endpoint should belong to
+ * @param cfg          - session parameters
+ * @param id           - created session identifier will be placed here
+ * @return zrtp_status_ok on success or some of zrtp_status_t error codes on failure
+ */
+zrtp_status_t zrtp_test_session_create(zrtp_test_id_t endpoint,
+                                                                          zrtp_test_session_cfg_t *cfg,
+                                                                          zrtp_test_id_t *id);
+
+zrtp_status_t zrtp_test_session_destroy(zrtp_test_id_t id);
+
+zrtp_status_t zrtp_test_session_get(zrtp_test_id_t id, zrtp_test_session_info_t *info);
+
+/**
+ * Get stream Id by it's index in zrtp session
+ *
+ * @param session_id   - zrtp test session id where needed stream should be taken
+ * @param idx          - stream index
+ * @return found stream id, or ZRTP_TEST_UNKNOWN_ID if idex is out of stream array range
+ */
+zrtp_test_id_t zrtp_test_session_get_stream_by_idx(zrtp_test_id_t session_id, unsigned idx);
+
+zrtp_status_t zrtp_test_stream_get(zrtp_test_id_t id, zrtp_test_stream_info_t *info);
+
+zrtp_status_t zrtp_test_channel_create(zrtp_test_id_t left_stream, zrtp_test_id_t right_stream, zrtp_test_id_t *id);
+zrtp_status_t zrtp_test_channel_create2(zrtp_test_id_t left_session, zrtp_test_id_t right_session, unsigned stream_idx, zrtp_test_id_t *id);
+zrtp_status_t zrtp_test_channel_destroy(zrtp_test_id_t id);
+zrtp_status_t zrtp_test_channel_start(zrtp_test_id_t id);
+zrtp_status_t zrtp_test_channel_get(zrtp_test_id_t id, zrtp_test_channel_info_t *info);
+
+zrtp_stream_t *zrtp_stream_for_test_stream(zrtp_test_id_t stream_id);
+
+unsigned zrtp_stream_did_event_receive(zrtp_test_id_t stream_id, unsigned event);
+
+