diff --git a/libs/libzrtp/build/test/Makefile.am b/libs/libzrtp/build/test/Makefile.am index b8f9a9abb9..4a9321c69f 100644 --- a/libs/libzrtp/build/test/Makefile.am +++ b/libs/libzrtp/build/test/Makefile.am @@ -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 index 0000000000..ef0973b9f3 --- /dev/null +++ b/libs/libzrtp/test/enroll_test_helpers.c @@ -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 index 0000000000..5d54c55478 --- /dev/null +++ b/libs/libzrtp/test/enrollment_test.c @@ -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 + */ + +#include /*chmockery dependency*/ +#include /*chmockery dependency*/ +#include /*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 index 0000000000..ab6740d3cc --- /dev/null +++ b/libs/libzrtp/test/go_secure_test.c @@ -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 + */ + +#include /*chmockery dependency*/ +#include /*chmockery dependency*/ +#include /*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 index ae3a7ec7c1..0000000000 --- a/libs/libzrtp/test/pc/zrtp_test_core.c +++ /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 - */ - -#include "zrtp.h" - -#include "zrtp_test_core.h" -#include "zrtp_test_queue.h" - -#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE) -#include -#elif (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_LINUX) -#include -#include -#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; ises_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; ises_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; istreams_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; istreams_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; ises_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; istreams_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; iStart 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; ises_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; ises_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 index 4a99fac328..0000000000 --- a/libs/libzrtp/test/pc/zrtp_test_core.h +++ /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 - */ - -#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 index bc1d6e2a08..0000000000 --- a/libs/libzrtp/test/pc/zrtp_test_ui.c +++ /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 - */ - -#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; -} diff --git a/libs/libzrtp/test/pc/zrtp_test_queue.c b/libs/libzrtp/test/queue.c similarity index 85% rename from libs/libzrtp/test/pc/zrtp_test_queue.c rename to libs/libzrtp/test/queue.c index 488f36f3c3..4b0d9b8194 100644 --- a/libs/libzrtp/test/pc/zrtp_test_queue.c +++ b/libs/libzrtp/test/queue.c @@ -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); diff --git a/libs/libzrtp/test/pc/zrtp_test_queue.h b/libs/libzrtp/test/queue.h similarity index 96% rename from libs/libzrtp/test/pc/zrtp_test_queue.h rename to libs/libzrtp/test/queue.h index 17ecec80af..6a0cbe2bfe 100644 --- a/libs/libzrtp/test/pc/zrtp_test_queue.h +++ b/libs/libzrtp/test/queue.h @@ -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 index 0000000000..5148c6a724 --- /dev/null +++ b/libs/libzrtp/test/sasrelay_test.c @@ -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 + */ + +#include /*chmockery dependency*/ +#include /*chmockery dependency*/ +#include /*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 index 0000000000..3b40985f57 --- /dev/null +++ b/libs/libzrtp/test/test_engine.c @@ -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 + */ + +#include /* for sprintf(), remove() */ +#include /* 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; isessions_count; i++) { + for (j=0; jsessions[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 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; igenerate_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; isize = 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; istreams_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; istreams_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; iid == ZRTP_TEST_UNKNOWN_ID) + continue; + + for (j=0; jsessions_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; iid == ZRTP_TEST_UNKNOWN_ID) + continue; + + for (j=0; jsessions_count; j++) { + zrtp_test_session_t *session = &endpoint->sessions[j]; + if (session->id == ZRTP_TEST_UNKNOWN_ID) + continue; + + for (k=0; kstreams_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; iid == 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 + */ + +#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); + +