Add high-level test engine

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>
This commit is contained in:
Viktor Krykun 2012-06-13 15:23:30 +03:00 committed by Travis Cross
parent a7286bff1a
commit 2664e0ee70
12 changed files with 1406 additions and 1004 deletions

View 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:

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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__*/

View File

@ -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;
}

View 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);

View 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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);