Fix security handshake test

Isolate domains by using unique tags when running tests that are using security handshake.
And updated coding style and some minor refactoring in fsm and timed_cb tests.

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>
This commit is contained in:
Dennis Potman 2020-03-04 11:14:51 +01:00 committed by eboasson
parent ea10dbd8e1
commit e7f5ae354c
9 changed files with 990 additions and 1333 deletions

View file

@ -62,8 +62,8 @@ function(add_wrapper libname linklibs)
endfunction()
set(security_core_test_sources
"tc_fsm.c"
"dds_security_core.c"
"fsm.c"
"timed_cb.c"
"security_utils.c"
)
@ -102,8 +102,6 @@ target_include_directories(
set(common_etc_dir "${CMAKE_CURRENT_SOURCE_DIR}/common/etc")
set(plugin_wrapper_lib_dir "${CMAKE_CURRENT_BINARY_DIR}")
file(TO_NATIVE_PATH "/" file_path_sep)
string(REPLACE "\\" "\\\\" file_path_sep ${file_path_sep})
configure_file("common/config_env.h.in" "common/config_env.h")
target_link_libraries(cunit_security_core PRIVATE ddsc security_api SecurityCoreTests)

View file

@ -19,6 +19,7 @@
#include "dds/version.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/environ.h"
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/string.h"
#include "dds/ddsi/q_config.h"
@ -36,8 +37,11 @@
static const char *config =
"${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}"
"<Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
"<Domain id=\"any\">"
" <Discovery>"
" <ExternalDomainId>0</ExternalDomainId>"
" <Tag>\\${CYCLONEDDS_PID}</Tag>"
" </Discovery>"
" <Tracing><Verbosity>config</></>"
" <DDSSecurity>"
" <Authentication>"
@ -87,8 +91,8 @@ static void authentication_init(bool different_ca, const char * trusted_ca_dir,
{ NULL, NULL, 0 }
};
char *conf1 = ddsrt_expand_vars (config, &expand_lookup_vars_env, config_vars1);
char *conf2 = ddsrt_expand_vars (config, &expand_lookup_vars_env, config_vars2);
char *conf1 = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars1);
char *conf2 = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars2);
CU_ASSERT_EQUAL_FATAL (expand_lookup_unmatched (config_vars1), 0);
CU_ASSERT_EQUAL_FATAL (expand_lookup_unmatched (config_vars2), 0);
g_domain1 = dds_create_domain (DDS_DOMAINID1, conf1);

View file

@ -12,7 +12,7 @@
#ifndef CONFIG_ENV_H
#define CONFIG_ENV_H
#define FILE_PATH_SEP "@file_path_sep@"
#define FILE_PATH_SEP "/"
#define COMMON_ETC_DIR "@common_etc_dir@"
#define PLUGIN_WRAPPER_LIB_DIR "@plugin_wrapper_lib_dir@"
#define PLUGIN_WRAPPER_LIB_PREFIX "@CMAKE_SHARED_LIBRARY_PREFIX@"

View file

@ -1,546 +0,0 @@
/*
* Copyright(c) 2019 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <stdio.h>
#include "CUnit/Test.h"
#include "dds/security/core/dds_security_timed_cb.h"
#include "dds/ddsrt/misc.h"
#define SEQ_SIZE (16)
typedef struct {
struct dds_security_timed_dispatcher_t *d;
dds_security_timed_cb_kind kind;
void *listener;
void *arg;
dds_time_t time;
} tc__sequence_data;
static int g_sequence_idx = 0;
static tc__sequence_data g_sequence_array[SEQ_SIZE];
static void simple_callback(struct dds_security_timed_dispatcher_t *d,
dds_security_timed_cb_kind kind,
void *listener,
void *arg)
{
DDSRT_UNUSED_ARG(d);
DDSRT_UNUSED_ARG(kind);
DDSRT_UNUSED_ARG(listener);
if (*((bool *)arg) == false)
{
*((bool *)arg) = true;
}
else
{
*((bool *)arg) = false;
}
}
static int g_order_callback_idx = 0;
static void* g_order_callback[2] = {(void*)NULL, (void*)NULL};
static void order_callback(struct dds_security_timed_dispatcher_t *d,
dds_security_timed_cb_kind kind,
void *listener,
void *arg)
{
DDSRT_UNUSED_ARG(d);
DDSRT_UNUSED_ARG(kind);
DDSRT_UNUSED_ARG(listener);
g_order_callback[g_order_callback_idx] = arg;
g_order_callback_idx++;
}
static void
tc__callback(
struct dds_security_timed_dispatcher_t *d,
dds_security_timed_cb_kind kind,
void *listener,
void *arg)
{
if (g_sequence_idx < SEQ_SIZE) {
g_sequence_array[g_sequence_idx].d = d;
g_sequence_array[g_sequence_idx].arg = arg;
g_sequence_array[g_sequence_idx].kind = kind;
g_sequence_array[g_sequence_idx].listener = listener;
g_sequence_array[g_sequence_idx].time = dds_time();
}
g_sequence_idx++;
}
CU_Test(dds_security_timed_cb, simple_test)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
struct dds_security_timed_dispatcher_t *d1 = NULL;
static bool test_var = false;
dds_time_t now = dds_time();
dds_time_t future = now + DDS_SECS(2);
d1 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
dds_security_timed_dispatcher_add(tcb, d1, simple_callback, future, (void*)&test_var);
dds_security_timed_dispatcher_enable(tcb, d1, (void*)NULL);
CU_ASSERT_FALSE_FATAL(test_var);
dds_sleepfor(DDS_MSECS(500));
CU_ASSERT_FALSE_FATAL(test_var);
dds_sleepfor(DDS_SECS(2));
CU_ASSERT_TRUE_FATAL(test_var);
dds_security_timed_dispatcher_free(tcb, d1);
dds_security_timed_cb_free(tcb);
}
CU_Test(dds_security_timed_cb, simple_order)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
struct dds_security_timed_dispatcher_t *d1 = NULL;
dds_time_t future;
dds_time_t future2;
d1 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
future = dds_time() + DDS_MSECS(20);
future2 = future;
dds_security_timed_dispatcher_add(tcb, d1, order_callback, future, (void*)1);
dds_security_timed_dispatcher_add(tcb, d1, order_callback, future2, (void*)2);
dds_security_timed_dispatcher_enable(tcb, d1, (void*)&g_order_callback);
dds_sleepfor(DDS_MSECS(10));
dds_security_timed_dispatcher_free(tcb, d1);
CU_ASSERT_EQUAL_FATAL(g_order_callback[0], (void*)1);
CU_ASSERT_EQUAL_FATAL(g_order_callback[1], (void*)2);
dds_security_timed_cb_free(tcb);
}
CU_Test(dds_security_timed_cb, test_enabled_and_disabled)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
struct dds_security_timed_dispatcher_t *d1 = NULL;
static bool test_var = false;
dds_time_t now = dds_time();
dds_time_t future = now + DDS_SECS(2);
d1 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
dds_security_timed_dispatcher_add(tcb, d1, simple_callback, future, (void*)&test_var);
dds_security_timed_dispatcher_enable(tcb, d1, (void*)NULL);
CU_ASSERT_FALSE(test_var);
dds_security_timed_dispatcher_disable(tcb, d1);
dds_sleepfor(DDS_MSECS(500));
CU_ASSERT_FALSE(test_var);
dds_sleepfor(DDS_SECS(2));
CU_ASSERT_FALSE(test_var);
dds_security_timed_dispatcher_free(tcb, d1);
dds_security_timed_cb_free(tcb);
}
CU_Test(dds_security_timed_cb, simple_test_with_future)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
struct dds_security_timed_dispatcher_t *d1 = NULL;
static bool test_var = false;
dds_time_t now = dds_time();
dds_time_t future = now + DDS_SECS(2);
dds_time_t far_future = now + DDS_SECS(10);
d1 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
dds_security_timed_dispatcher_enable(tcb, d1, (void*)NULL);
dds_security_timed_dispatcher_add(tcb, d1, simple_callback, future, (void*)&test_var);
dds_security_timed_dispatcher_add(tcb, d1, simple_callback, far_future, (void*)&test_var);
CU_ASSERT_FALSE_FATAL(test_var);
dds_sleepfor(DDS_MSECS(500));
CU_ASSERT_FALSE_FATAL(test_var);
dds_sleepfor(DDS_SECS(2));
CU_ASSERT_TRUE_FATAL(test_var);
dds_security_timed_dispatcher_free(tcb, d1);
dds_security_timed_cb_free(tcb);
}
CU_Test(dds_security_timed_cb, test_multiple_dispatchers)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
struct dds_security_timed_dispatcher_t *d1 = NULL;
struct dds_security_timed_dispatcher_t *d2 = NULL;
static bool test_var = false;
dds_time_t now = dds_time();
dds_time_t future = now + DDS_SECS(2);
dds_time_t far_future = now + DDS_SECS(10);
d1 = dds_security_timed_dispatcher_new(tcb);
d2 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
dds_security_timed_dispatcher_enable(tcb, d1, (void*)NULL);
dds_security_timed_dispatcher_enable(tcb, d2, (void*)NULL);
dds_security_timed_dispatcher_free(tcb, d2);
dds_security_timed_dispatcher_add(tcb, d1, simple_callback, future, (void*)&test_var);
dds_security_timed_dispatcher_add(tcb, d1, simple_callback, far_future, (void*)&test_var);
CU_ASSERT_FALSE_FATAL(test_var);
dds_sleepfor(DDS_MSECS(500));
CU_ASSERT_FALSE_FATAL(test_var);
dds_sleepfor(DDS_SECS(2));
CU_ASSERT_TRUE_FATAL(test_var);
dds_security_timed_dispatcher_free(tcb, d1);
dds_security_timed_cb_free(tcb);
}
CU_Test(dds_security_timed_cb, test_not_enabled_multiple_dispatchers)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
struct dds_security_timed_dispatcher_t *d1 = NULL;
struct dds_security_timed_dispatcher_t *d2 = NULL;
d1 = dds_security_timed_dispatcher_new(tcb);
d2 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
CU_ASSERT_PTR_NOT_NULL_FATAL(d2);
dds_security_timed_dispatcher_free(tcb, d2);
dds_security_timed_dispatcher_free(tcb, d1);
dds_security_timed_cb_free(tcb);
CU_PASS("Timed callbacks enabled and disabled without add");
}
CU_Test(dds_security_timed_cb, test_create_dispatcher)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
struct dds_security_timed_dispatcher_t *d1 = NULL;
struct dds_security_timed_dispatcher_t *d2 = NULL;
struct dds_security_timed_dispatcher_t *d3 = NULL;
struct dds_security_timed_dispatcher_t *d4 = NULL;
struct dds_security_timed_dispatcher_t *d5 = NULL;
bool ok = false;
dds_time_t now = dds_time();
dds_time_t past = now - DDS_SECS(1);
dds_time_t present = now + DDS_SECS(1);
dds_time_t future = present + DDS_SECS(1);
dds_time_t future2 = future + DDS_SECS(10);
/*************************************************************************
* Check if dispatchers can be created
*************************************************************************/
d1 = dds_security_timed_dispatcher_new(tcb);
d2 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
CU_ASSERT_PTR_NOT_NULL_FATAL(d2);
/*************************************************************************
* Check if adding callbacks succeeds
*************************************************************************/
/* The last argument is a sequence number in which
* the callbacks are expected to be called. */
/* We can only really check if it crashes or not... */
dds_security_timed_dispatcher_add(tcb, d1, tc__callback, present, (void*)1);
dds_security_timed_dispatcher_add(tcb, d2, tc__callback, past, (void*)0);
dds_security_timed_dispatcher_add(tcb, d2, tc__callback, present, (void*)2);
dds_security_timed_dispatcher_add(tcb, d1, tc__callback, future, (void*)7);
CU_PASS("Added callbacks")
/*************************************************************************
* Check if dispatchers can be created
*************************************************************************/
d3 = dds_security_timed_dispatcher_new(tcb);
d4 = dds_security_timed_dispatcher_new(tcb);
d5 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d3);
CU_ASSERT_PTR_NOT_NULL_FATAL(d4);
CU_ASSERT_PTR_NOT_NULL_FATAL(d5);
/*************************************************************************
* Check if enabling dispatchers succeeds
*************************************************************************/
/* The sleeps are added to get the timing between
* 'present' and 'past' callbacks right. */
/* We can only really check if it crashes or not... */
dds_sleepfor(DDS_MSECS(600));
dds_security_timed_dispatcher_enable(tcb, d1, (void*)NULL);
dds_security_timed_dispatcher_enable(tcb, d2, (void*) d2);
dds_security_timed_dispatcher_enable(tcb, d3, (void*)NULL);
/* Specifically not enabling d4 and d5. */
dds_sleepfor(DDS_MSECS(600));
CU_PASS("Enabled dds_security_timed_dispatchers.");
/*************************************************************************
* Check if adding callbacks succeeds
*************************************************************************/
/* The last argument is a sequence number in which
* the callbacks are expected to be called. */
/* We can only really check if it crashes or not... */
dds_security_timed_dispatcher_add(tcb, d4, tc__callback, past, (void*)99);
dds_security_timed_dispatcher_add(tcb, d2, tc__callback, future, (void*) 8);
dds_security_timed_dispatcher_add(tcb, d3, tc__callback, future2, (void*) 9);
dds_security_timed_dispatcher_add(tcb, d1, tc__callback, past, (void*) 3);
dds_security_timed_dispatcher_add(tcb, d1, tc__callback, future2, (void*)10);
dds_security_timed_dispatcher_add(tcb, d1, tc__callback, present, (void*) 4);
dds_security_timed_dispatcher_add(tcb, d2, tc__callback, present, (void*) 5);
dds_security_timed_dispatcher_add(tcb, d1, tc__callback, future, (void*) 6);
dds_security_timed_dispatcher_add(tcb, d3, tc__callback, future2, (void*)11);
CU_PASS("Added callbacks.");
/*************************************************************************
* Check if timeout callbacks are triggered in the right sequence
*************************************************************************/
int idx;
int timeout = 200; /* 2 seconds */
/* Wait for the callbacks to have been triggered.
* Ignore the ones in the far future. */
while ((g_sequence_idx < 8) && (timeout > 0)) {
dds_sleepfor(DDS_MSECS(10));
timeout--;
}
/* Print and check sequence of triggered callbacks. */
for (idx = 0; (idx < g_sequence_idx) && (idx < SEQ_SIZE); idx++) {
int seq = (int)(long long)(g_sequence_array[idx].arg);
struct dds_security_timed_dispatcher_t *expected_d;
void *expected_l;
/*
* Sequence checks.
*/
if ((seq == 1) || (seq == 6) || (seq == 3) || (seq == 10) || (seq == 4) || (seq == 7)) {
expected_d = d1;
expected_l = NULL;
} else if ((seq == 0) || (seq == 2) || (seq == 8) || (seq == 5)) {
expected_d = d2;
expected_l = d2;
} else if (seq == 9) {
expected_d = d3;
expected_l = NULL;
} else if (seq == 99) {
expected_d = d4;
expected_l = NULL;
CU_FAIL("Unexpected callback on a disabled dispatcher");
ok = false;
} else {
expected_d = NULL;
expected_l = NULL;
CU_FAIL(sprintf("Unknown sequence idx received %d", seq));
ok = false;
}
if (seq != idx) {
/* 6 and 7 order may be mixed since the order is not defined for same time stamp */
if (!((seq == 6 && idx == 7) || (seq == 7 && idx == 6)))
{
printf("Unexpected sequence ordering %d vs %d\n", seq, idx);
CU_FAIL("Unexpected sequence ordering");
ok = false;
}
}
if (seq > 8) {
CU_FAIL(sprintf("Unexpected sequence idx %d of the far future", seq));
ok = false;
}
if (idx > 8) {
CU_FAIL(sprintf("Too many callbacks %d", idx));
ok = false;
}
/*
* Callback contents checks.
*/
if (expected_d != NULL) {
if (g_sequence_array[idx].d != expected_d) {
printf("Unexpected dispatcher %p vs %p\n", g_sequence_array[idx].d, expected_d);
CU_FAIL("Unexpected dispatcher");
ok = false;
}
if (g_sequence_array[idx].listener != expected_l) {
CU_FAIL(sprintf("Unexpected listener %p vs %p", g_sequence_array[idx].listener, expected_l));
ok = false;
}
}
/*
* Callback kind check.
*/
if (g_sequence_array[idx].kind != DDS_SECURITY_TIMED_CB_KIND_TIMEOUT) {
CU_FAIL(sprintf("Unexpected kind %d vs %d", (int)g_sequence_array[idx].kind, (int)DDS_SECURITY_TIMED_CB_KIND_TIMEOUT));
ok = false;
}
}
if (g_sequence_idx < 8) {
CU_FAIL(sprintf("Received %d callbacks, while 9 are expected",
g_sequence_idx + 1));
ok = false;
}
if (ok) {
CU_FAIL(sprintf("Received timeout callbacks."));
}
/* Reset callback index to catch the deletion ones. */
g_sequence_idx = 0;
/*************************************************************************
* Check if deleting succeeds with dispatchers in different states
*************************************************************************/
/* We can only really check if it crashes or not... */
if (d1) {
dds_security_timed_dispatcher_free(tcb, d1);
}
if (d2) {
dds_security_timed_dispatcher_free(tcb, d2);
}
if (d3) {
dds_security_timed_dispatcher_free(tcb, d3);
}
if (d4) {
dds_security_timed_dispatcher_free(tcb, d4);
}
if (d5) {
dds_security_timed_dispatcher_free(tcb, d5);
}
CU_PASS("Deleted dispatchers.");
/*************************************************************************
* Check if deletion callbacks are triggered
*************************************************************************/
if (ok) {
timeout = 200; /* 2 seconds */
/* Wait for the callbacks to have been triggered.
* Ignore the ones in the far future. */
while ((g_sequence_idx < 4) && (timeout > 0)) {
dds_sleepfor(DDS_MSECS(10));
timeout--;
}
/* Print and check sequence of triggered callbacks. */
for (idx = 0; (idx < g_sequence_idx) && (idx < SEQ_SIZE); idx++) {
int seq = (int)(long long)(g_sequence_array[idx].arg);
struct dds_security_timed_dispatcher_t *expected_d;
/*
* Human (somewhat) readable format.
*/
// tc__sequence_data_print(&(g_sequence_array[idx]));
/*
* Sequence checks.
*/
if (seq == 99) {
expected_d = d4;
} else if ((seq == 9) || (seq == 11)) {
expected_d = d3;
} else if (seq == 10) {
expected_d = d1;
} else {
expected_d = NULL;
CU_FAIL(sprintf("Unexpected sequence idx received %d", seq));
ok = false;
}
if (idx > 4) {
CU_FAIL(sprintf("Too many callbacks %d", idx));
ok = false;
}
/*
* Callback contents checks.
*/
if (expected_d != NULL) {
if (g_sequence_array[idx].d != expected_d) {
CU_FAIL(sprintf("Unexpected dispatcher %p vs %p", g_sequence_array[idx].d, expected_d));
ok = false;
}
if (g_sequence_array[idx].listener != NULL) {
CU_FAIL(sprintf("Unexpected listener %p vs NULL", g_sequence_array[idx].listener));
ok = false;
}
}
/*
* Callback kind check.
*/
if (g_sequence_array[idx].kind != DDS_SECURITY_TIMED_CB_KIND_DELETE) {
CU_FAIL(sprintf("Unexpected kind %d vs %d", (int)g_sequence_array[idx].kind, (int)DDS_SECURITY_TIMED_CB_KIND_TIMEOUT));
ok = false;
}
}
if (g_sequence_idx < 4) {
CU_FAIL(sprintf("Received %d callbacks, while 3 are expected",
g_sequence_idx + 1));
ok = false;
}
if (ok) {
CU_PASS("Received deletion callbacks.");
}
}
dds_security_timed_cb_free(tcb);
}

View file

@ -0,0 +1,581 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <stdio.h>
#include <stdbool.h>
#include "CUnit/CUnit.h"
#include "CUnit/Test.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/misc.h"
#include "dds/dds.h"
#include "dds__types.h"
#include "dds__entity.h"
#include "dds/security/core/dds_security_fsm.h"
#define CHECK_BIT(var, pos) ((var) & (1<<(pos)))
#define FSM_AUTH_ARG 10
static dds_entity_t g_participant = 0;
static ddsrt_mutex_t g_lock;
static struct dds_security_fsm_control *g_fsm_control = NULL;
#define DO_SIMPLE(name, var, bit) static void name(struct dds_security_fsm *fsm, void *arg) { \
DDSRT_UNUSED_ARG(fsm); \
DDSRT_UNUSED_ARG(arg); \
printf("Transition %s\n", __FUNCTION__); \
ddsrt_mutex_lock(&g_lock); \
visited_##var |= 1u << (bit); \
ddsrt_mutex_unlock(&g_lock); \
}
typedef enum {
VALIDATION_PENDING_RETRY,
VALIDATION_FAILED,
VALIDATION_OK,
VALIDATION_OK_FINAL_MESSAGE,
VALIDATION_PENDING_HANDSHAKE_MESSAGE,
VALIDATION_PENDING_HANDSHAKE_REQUEST,
plugin_ret_MAX
} plugin_ret;
static struct dds_security_fsm *fsm_auth;
static uint32_t visited_auth = 0;
static uint32_t correct_fsm = 0;
static uint32_t correct_arg = 0;
static int validate_remote_identity_first = 1;
static int begin_handshake_reply_first = 1;
static plugin_ret validate_remote_identity(void)
{
printf("validate_remote_identity - %d\n", validate_remote_identity_first);
if (validate_remote_identity_first)
{
validate_remote_identity_first = 0;
return VALIDATION_PENDING_RETRY;
}
return VALIDATION_PENDING_HANDSHAKE_MESSAGE;
}
static plugin_ret begin_handshake_reply(void)
{
printf("begin_handshake_reply - %d\n", begin_handshake_reply_first);
if (begin_handshake_reply_first)
{
begin_handshake_reply_first = 0;
return VALIDATION_PENDING_RETRY;
}
return VALIDATION_OK_FINAL_MESSAGE;
}
static plugin_ret get_shared_secret(void)
{
return VALIDATION_OK;
}
/* State actions */
static void fsm_validate_remote_identity(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(arg);
plugin_ret ret = validate_remote_identity();
printf("[%p] State %s (ret %d)\n", fsm, __FUNCTION__, (int) ret);
dds_security_fsm_dispatch(fsm, (int32_t) ret, false);
}
static void fsm_begin_handshake_reply(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(arg);
plugin_ret ret = begin_handshake_reply();
if (ret == VALIDATION_OK_FINAL_MESSAGE)
ret = get_shared_secret();
printf("[%p] State %s (ret %d)\n", fsm, __FUNCTION__, (int) ret);
dds_security_fsm_dispatch(fsm, (int32_t) ret, false);
}
/* A few states from the handshake state-machine. */
static dds_security_fsm_state StateValidateRemoteIdentity = {fsm_validate_remote_identity, 0};
static dds_security_fsm_state StateValRemIdentityRetryWait = {NULL, 100000000};
static dds_security_fsm_state StateHandshakeInitMessageWait = {NULL, 0};
static dds_security_fsm_state state_beginHandshakeReply = {fsm_begin_handshake_reply, 0};
static dds_security_fsm_state state_beginHsReplyWait = {NULL, 100000000};
static void a(struct dds_security_fsm *fsm, void *arg)
{
printf("[%p] Transition %s\n", fsm, __FUNCTION__);
ddsrt_mutex_lock (&g_lock);
if (arg != NULL)
correct_arg = *((int *)arg) == FSM_AUTH_ARG ? 1 : 0;
correct_fsm = (fsm == fsm_auth) ? 1 : 0;
visited_auth |= 1u << 0;
ddsrt_mutex_unlock (&g_lock);
}
DO_SIMPLE(b, auth, 1)
DO_SIMPLE(c, auth, 2)
DO_SIMPLE(d, auth, 3)
DO_SIMPLE(e, auth, 4)
DO_SIMPLE(f, auth, 5)
DO_SIMPLE(g, auth, 6)
DO_SIMPLE(h, auth, 7)
#define SHM_MSG_RECEIVED (plugin_ret_MAX + 1)
/*
* .--.
* |##|--------------------------------------.
* '--' a() v
* .----------------------------------------------------.
* | StateValidateRemoteIdentity |
* |----------------------------------------------------|
* .------>| fsm_validate_remote_identity() |
* | | - dispatch VALIDATION_PENDING_RETRY |
* 100ms| | - dispatch VALIDATION_PENDING_HANDSHAKE_MESSAGE |
* d() | '----------------------------------------------------'
* | VALIDATION_PENDING_RETRY| | VALIDATION_PENDING_HANDSHAKE_MESSAGE
* | b() | | c()
* | | |
* .------------------------------. | | .-------------------------------.
* | StateValRemIdentityRetryWait | | | | StateHandshakeInitMessageWait |
* |------------------------------|<----------' '------>|-------------------------------|
* '------------------------------' '-------------------------------'
* SHM_MSG_RECEIVED |
* e() |
* v
* .----------------------------------------.
* VALIDATION_PENDING_RETRY | state_beginHandshakeReply |
* f() |----------------------------------------|
* .-------------------------| fsm_begin_handshake_reply() |
* | | - dispatch VALIDATION_PENDING_RETRY |
* v | - dispatch VALIDATION_OK |
* .-----------------------. 100ms '----------------------------------------'
* | state_beginHsReplyWait | h() ^ VALIDATION_OK |
* |-----------------------|-----------------------' g() |
* '-----------------------' v
* .-.
* '-'
*/
static dds_security_fsm_transition HandshakeTransistions[] = {
{NULL, DDS_SECURITY_FSM_EVENT_AUTO, a, &StateValidateRemoteIdentity}, // NULL state is the start state
{&StateValidateRemoteIdentity, VALIDATION_PENDING_RETRY, b, &StateValRemIdentityRetryWait},
{&StateValidateRemoteIdentity, VALIDATION_PENDING_HANDSHAKE_MESSAGE, c, &StateHandshakeInitMessageWait},
{&StateValRemIdentityRetryWait, DDS_SECURITY_FSM_EVENT_TIMEOUT, d, &StateValidateRemoteIdentity},
{&StateHandshakeInitMessageWait, SHM_MSG_RECEIVED, e, &state_beginHandshakeReply},
{&state_beginHandshakeReply, VALIDATION_PENDING_RETRY, f, &state_beginHsReplyWait},
{&state_beginHandshakeReply, VALIDATION_OK, g, NULL}, // Reaching NULL means end of state-diagram
{&state_beginHsReplyWait, DDS_SECURITY_FSM_EVENT_TIMEOUT, h, &state_beginHandshakeReply}
};
static const uint32_t HandshakeTransistionsSize = sizeof(HandshakeTransistions)/sizeof(HandshakeTransistions[0]);
/* Example State Machine properties and methods */
typedef enum {
eventX, eventY, eventZ,
} test_events;
static struct dds_security_fsm *fsm_test;
static uint32_t visited_test = 0;
static int do_stuff_counter = 0;
static int do_other_stuff_counter = 0;
DO_SIMPLE(do_start, test, 0)
DO_SIMPLE(do_restart, test, 1)
DO_SIMPLE(do_event_stuff, test, 4)
static void do_stuff(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(fsm);
DDSRT_UNUSED_ARG(arg);
printf("Transition %s - %d\n", __FUNCTION__, do_stuff_counter);
ddsrt_mutex_lock (&g_lock);
visited_test |= 1u << 2;
ddsrt_mutex_unlock (&g_lock);
if (do_stuff_counter < 2)
dds_security_fsm_dispatch(fsm, eventZ, false);
else if (do_stuff_counter == 2)
dds_security_fsm_dispatch(fsm, eventY, false);
++do_stuff_counter;
}
static void do_other_stuff(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(fsm);
DDSRT_UNUSED_ARG(arg);
printf("Transition %s - %d\n", __FUNCTION__, do_other_stuff_counter);
ddsrt_mutex_lock (&g_lock);
visited_test |= 1u << 3;
ddsrt_mutex_unlock (&g_lock);
if (do_other_stuff_counter == 0)
dds_security_fsm_dispatch(fsm, DDS_SECURITY_FSM_EVENT_AUTO, false);
else if (do_other_stuff_counter == 1)
dds_security_fsm_dispatch(fsm, eventY, false);
else if (do_other_stuff_counter == 2)
dds_security_fsm_dispatch(fsm, eventX, false);
++do_other_stuff_counter;
}
static dds_security_fsm_state state_a = {do_stuff, 0};
static dds_security_fsm_state state_b = {do_stuff, 100000000};
static dds_security_fsm_state state_c = {NULL, 0};
static dds_security_fsm_state state_d = {do_other_stuff, 0};
static dds_security_fsm_transition Transitions[] = {
{NULL, DDS_SECURITY_FSM_EVENT_AUTO, do_start, &state_a}, // NULL state is the start state
{&state_a, eventZ, NULL, &state_b},
{&state_a, eventY, do_other_stuff, &state_c},
{&state_b, eventX, NULL, NULL}, // Reaching NULL means end of state-diagram
{&state_b, eventZ, do_restart, &state_a},
{&state_c, DDS_SECURITY_FSM_EVENT_AUTO, do_event_stuff, &state_d},
{&state_d, eventY, do_event_stuff, &state_d},
{&state_d, eventX, do_stuff, NULL}, // Reaching NULL means end of sttimeoutate-diagram
};
static const uint32_t TransitionsSize = sizeof(Transitions)/sizeof(Transitions[0]);
/* Timeout State Machine properties and methods */
typedef enum {
event_to_timeout, event_to_interrupt, event_to_end,
} timeout_events;
struct fsm_timeout_arg {
int id;
};
static struct dds_security_fsm *fsm_timeout;
static uint32_t visited_timeout = 0;
static uint32_t correct_fsm_timeout = 0;
static uint32_t correct_arg_timeout = 0;
static struct fsm_timeout_arg fsm_arg = { .id = FSM_AUTH_ARG };
DO_SIMPLE(do_interrupt, timeout, 0)
DO_SIMPLE(timeout_cb2, timeout, 3)
static void do_timeout(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(arg);
printf("Transition >>>> %s\n", __FUNCTION__);
ddsrt_mutex_lock (&g_lock);
visited_timeout |= 1u << 1;
ddsrt_mutex_unlock (&g_lock);
printf("Transition <<<< %s\n", __FUNCTION__);
dds_security_fsm_dispatch(fsm, event_to_timeout, false);
}
static void timeout_cb(struct dds_security_fsm *fsm, void *arg)
{
struct fsm_timeout_arg *farg = arg;
printf("timeout_cb\n");
ddsrt_mutex_lock (&g_lock);
visited_timeout |= 1u << 2;
if (farg != NULL)
correct_arg_timeout = farg->id == FSM_AUTH_ARG ? 1 : 0;
correct_fsm_timeout = fsm == fsm_timeout ? 1 : 0;
ddsrt_mutex_unlock (&g_lock);
}
static dds_security_fsm_state state_initial = {do_timeout, 0};
static dds_security_fsm_state state_wait_timeout = {NULL, DDS_SECS(4)};
static dds_security_fsm_state state_interrupt = {do_interrupt, 0};
static const dds_security_fsm_transition timeout_transitions[] = {
{NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &state_initial}, // NULL state is the start state
{&state_initial, event_to_timeout, NULL, &state_wait_timeout},
{&state_wait_timeout, DDS_SECURITY_FSM_EVENT_TIMEOUT, NULL, &state_interrupt},
{&state_wait_timeout, event_to_interrupt, NULL, &state_interrupt},
{&state_interrupt, event_to_end, NULL, NULL}, // Reaching NULL means end of state-diagram
};
static const uint32_t timeout_transitionsSize = sizeof(timeout_transitions)/sizeof(timeout_transitions[0]);
/* Parallel Timeout State Machines properties and methods */
static struct dds_security_fsm *fsm_timeout1;
static struct dds_security_fsm *fsm_timeout2;
static struct dds_security_fsm *fsm_timeout3;
static dds_time_t time0 = 0;
static dds_time_t time1 = 0;
static dds_time_t time2 = 0;
static dds_time_t time3 = 0;
static void state_par_time1(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(fsm);
DDSRT_UNUSED_ARG(arg);
time1 = dds_time();
}
static void state_par_time2(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(fsm);
DDSRT_UNUSED_ARG(arg);
time2 = dds_time();
}
static void state_par_time3(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(fsm);
DDSRT_UNUSED_ARG(arg);
time3 = dds_time();
}
static dds_security_fsm_state state_par_timeout1 = {NULL, DDS_SECS(1)};
static dds_security_fsm_state state_par_timeout2 = {NULL, DDS_SECS(2)};
static dds_security_fsm_state state_par_timeout3 = {NULL, DDS_SECS(1)};
static dds_security_fsm_transition parallel_timeout_transitions_1[] = {
{NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &state_par_timeout1}, // NULL state is the startfsm_control_thread state
{&state_par_timeout1, DDS_SECURITY_FSM_EVENT_TIMEOUT, &state_par_time1, NULL}, // Reaching NULL means end of state-diagram
};
static const uint32_t parallel_timeout_transitionsSize_1 = sizeof(parallel_timeout_transitions_1) / sizeof(parallel_timeout_transitions_1[0]);
static dds_security_fsm_transition parallel_timeout_transitions_2[] = {
{NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &state_par_timeout2}, // NULL state is the start state
{&state_par_timeout2, DDS_SECURITY_FSM_EVENT_TIMEOUT, &state_par_time2, NULL}, // Reaching NULL means end of state-diagram
};
static const uint32_t parallel_timeout_transitionsSize_2 = sizeof(parallel_timeout_transitions_2) / sizeof(parallel_timeout_transitions_2[0]);
static dds_security_fsm_transition parallel_timeout_transitions_3[] = {
{NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &state_par_timeout3}, // NULL state is the start state
{&state_par_timeout3, DDS_SECURITY_FSM_EVENT_TIMEOUT, &state_par_time3, NULL}, // Reaching NULL means end of state-diagram
};
static const uint32_t parallel_timeout_transitionsSize_3 = sizeof(parallel_timeout_transitions_3) / sizeof(parallel_timeout_transitions_3[0]);
static void fsm_control_init(void)
{
struct dds_entity *e;
g_participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL(g_participant > 0);
ddsrt_mutex_init(&g_lock);
dds_return_t rc = dds_entity_pin(g_participant, &e);
CU_ASSERT_FATAL(rc == 0);
g_fsm_control = dds_security_fsm_control_create(&e->m_domain->gv);
CU_ASSERT_FATAL(g_fsm_control != NULL);
dds_entity_unpin(e);
rc = dds_security_fsm_control_start(g_fsm_control, NULL);
CU_ASSERT_EQUAL_FATAL(rc, 0);
}
static void fsm_control_fini(void)
{
dds_security_fsm_control_stop(g_fsm_control);
dds_security_fsm_control_free(g_fsm_control);
ddsrt_mutex_destroy (&g_lock);
dds_delete(g_participant);
}
CU_Test(ddssec_fsm, create, .init = fsm_control_init, .fini = fsm_control_fini)
{
/* Test single running state machine. Check creation of a single State Machine */
fsm_auth = dds_security_fsm_create(g_fsm_control, HandshakeTransistions, HandshakeTransistionsSize, &fsm_arg);
CU_ASSERT_FATAL(fsm_auth != NULL)
/* set a delay that doesn't expire. Should be terminate when fsm is freed. */
dds_security_fsm_set_timeout(fsm_auth, timeout_cb, DDS_SECS(30));
dds_security_fsm_start(fsm_auth);
int n = 100;
while (dds_security_fsm_current_state(fsm_auth) != &StateHandshakeInitMessageWait && n-- > 0)
dds_sleepfor(DDS_MSECS(100));
CU_ASSERT(n > 0);
dds_security_fsm_dispatch(fsm_auth, SHM_MSG_RECEIVED, false);
n = 100;
while (dds_security_fsm_current_state(fsm_auth) != NULL && n-- > 0)
dds_sleepfor(DDS_MSECS(100));
CU_ASSERT(n > 0);
ddsrt_mutex_lock (&g_lock);
CU_ASSERT(visited_auth == 0xff);
ddsrt_mutex_unlock (&g_lock);
/* Check correct callback parameter passing (from fsm to user defined methods) */
CU_ASSERT(correct_arg && correct_fsm);
dds_security_fsm_free(fsm_auth);
/* Check whether timeout callback has NOT been invoked */
ddsrt_mutex_lock (&g_lock);
CU_ASSERT(visited_timeout == 0);
ddsrt_mutex_unlock (&g_lock);
}
/* Test multiple (2) running state machines */
CU_Test(ddssec_fsm, multiple, .init = fsm_control_init, .fini = fsm_control_fini)
{
validate_remote_identity_first = 0;
begin_handshake_reply_first = 0;
visited_auth = 0;
visited_test = 0;
fsm_auth = dds_security_fsm_create(g_fsm_control, HandshakeTransistions, HandshakeTransistionsSize, NULL);
CU_ASSERT_FATAL(fsm_auth != NULL);
fsm_test = dds_security_fsm_create(g_fsm_control, Transitions, TransitionsSize, NULL);
CU_ASSERT_FATAL(fsm_test != NULL);
dds_security_fsm_start(fsm_auth);
dds_security_fsm_start(fsm_test);
/* Check the results of multiple running State Machines */
int n = 100; /* 10 sec */
while (dds_security_fsm_current_state(fsm_auth) != &StateHandshakeInitMessageWait && n-- > 0)
dds_sleepfor(DDS_MSECS(100));
CU_ASSERT_FATAL(n > 0);
n = 100; /* 10 sec */
dds_security_fsm_dispatch(fsm_auth, SHM_MSG_RECEIVED, false);
while (dds_security_fsm_current_state(fsm_auth) != NULL && n-- > 0)
dds_sleepfor(DDS_MSECS(100));
CU_ASSERT_FATAL(n > 0);
// not all bits are set since we're running the state machine a second time
ddsrt_mutex_lock (&g_lock);
CU_ASSERT_FATAL(visited_auth == 0x55);
ddsrt_mutex_unlock (&g_lock);
/* Wait for the last state to occur */
n = 100; /* 10 sec */
while (dds_security_fsm_current_state(fsm_test) != NULL && n-- > 0)
dds_sleepfor(DDS_MSECS(100));
CU_ASSERT_FATAL(n > 0);
ddsrt_mutex_lock (&g_lock);
CU_ASSERT(visited_test == 0x1f);
ddsrt_mutex_unlock (&g_lock);
dds_security_fsm_free(fsm_auth);
dds_security_fsm_free(fsm_test);
}
/**
* Check creation of State Machine for timeout purposes
*/
CU_Test(ddssec_fsm, timeout, .init = fsm_control_init, .fini = fsm_control_fini)
{
visited_timeout = 0;
/* Test timeout monitoring of state machines */
fsm_timeout = dds_security_fsm_create(g_fsm_control, timeout_transitions, timeout_transitionsSize, &fsm_arg);
CU_ASSERT(fsm_timeout != NULL);
dds_security_fsm_set_timeout(fsm_timeout, timeout_cb, DDS_SECS(1));
dds_security_fsm_start(fsm_timeout);
int n = 100; /* 10 sec */
ddsrt_mutex_lock (&g_lock);
while (visited_timeout != 0x7 && n-- > 0)
{
ddsrt_mutex_unlock (&g_lock);
dds_sleepfor(DDS_MSECS(100));
ddsrt_mutex_lock (&g_lock);
}
CU_ASSERT(n > 0);
CU_ASSERT(visited_timeout == 0x7);
CU_ASSERT(correct_arg_timeout && correct_fsm_timeout);
ddsrt_mutex_unlock (&g_lock);
dds_security_fsm_free(fsm_timeout);
}
/* Check the double global timeout */
CU_Test(ddssec_fsm, double_timeout, .init = fsm_control_init, .fini = fsm_control_fini)
{
visited_timeout = 0;
fsm_timeout = dds_security_fsm_create(g_fsm_control, timeout_transitions, timeout_transitionsSize, &fsm_arg);
CU_ASSERT(fsm_timeout != NULL);
fsm_timeout2 = dds_security_fsm_create(g_fsm_control, timeout_transitions, timeout_transitionsSize, &fsm_arg);
CU_ASSERT(fsm_timeout2 != NULL);
dds_security_fsm_set_timeout(fsm_timeout, timeout_cb, DDS_SECS(1));
dds_security_fsm_set_timeout(fsm_timeout2, timeout_cb2, DDS_SECS(2));
dds_security_fsm_start(fsm_timeout);
dds_security_fsm_start(fsm_timeout2);
int n = 100;
ddsrt_mutex_lock (&g_lock);
while (visited_timeout != 0xf && n-- > 0)
{
ddsrt_mutex_unlock (&g_lock);
dds_sleepfor(DDS_MSECS(100));
ddsrt_mutex_lock (&g_lock);
}
CU_ASSERT(visited_timeout == 0xf);
ddsrt_mutex_unlock (&g_lock);
dds_security_fsm_free(fsm_timeout);
dds_security_fsm_free(fsm_timeout2);
}
/* Check parallel state timeouts */
CU_Test(ddssec_fsm, parallel_timeout, .init = fsm_control_init, .fini = fsm_control_fini)
{
visited_timeout = 0;
fsm_timeout1 = dds_security_fsm_create(g_fsm_control, parallel_timeout_transitions_1, parallel_timeout_transitionsSize_1, &fsm_arg);
CU_ASSERT_FATAL(fsm_timeout1 != NULL);
fsm_timeout2 = dds_security_fsm_create(g_fsm_control, parallel_timeout_transitions_2, parallel_timeout_transitionsSize_2, &fsm_arg);
CU_ASSERT_FATAL(fsm_timeout2 != NULL);
fsm_timeout3 = dds_security_fsm_create(g_fsm_control, parallel_timeout_transitions_3, parallel_timeout_transitionsSize_3, &fsm_arg);
CU_ASSERT_FATAL(fsm_timeout3 != NULL);
time0 = dds_time();
dds_security_fsm_start(fsm_timeout1);
dds_security_fsm_start(fsm_timeout2);
dds_security_fsm_start(fsm_timeout3);
int n = 300;
while (((dds_security_fsm_current_state(fsm_timeout1) == NULL)
|| (dds_security_fsm_current_state(fsm_timeout2) == NULL)
|| (dds_security_fsm_current_state(fsm_timeout3) == NULL)) && n-- > 0)
{
dds_sleepfor(DDS_MSECS(100));
}
while (((dds_security_fsm_current_state(fsm_timeout1) != NULL)
|| (dds_security_fsm_current_state(fsm_timeout2) != NULL)
|| (dds_security_fsm_current_state(fsm_timeout3) != NULL)) && n-- > 0)
{
dds_sleepfor(DDS_MSECS(100));
}
dds_duration_t delta1 = time1 - time0;
dds_duration_t delta2 = time2 - time0;
dds_duration_t delta3 = time3 - time0;
printf("time0 %"PRId64"\n", time0);
printf("time1 %"PRId64", delta1 %"PRId64"\n", time1, delta1);
printf("time2 %"PRId64", delta2 %"PRId64"\n", time2, delta2);
printf("time3 %"PRId64", delta3 %"PRId64"\n", time3, delta3);
CU_ASSERT(delta1 > DDS_MSECS(750));
CU_ASSERT(delta1 < DDS_MSECS(1250));
CU_ASSERT(delta2 > DDS_MSECS(1750));
CU_ASSERT(delta2 < DDS_MSECS(2250));
CU_ASSERT(delta3 > DDS_MSECS(750));
CU_ASSERT(delta3 < DDS_MSECS(1250));
dds_security_fsm_free(fsm_timeout1);
dds_security_fsm_free(fsm_timeout2);
dds_security_fsm_free(fsm_timeout3);
}
/* Delete with event timeout */
CU_Test(ddssec_fsm, delete_with_timeout, .init = fsm_control_init, .fini = fsm_control_fini)
{
fsm_timeout = dds_security_fsm_create(g_fsm_control, timeout_transitions, timeout_transitionsSize, &fsm_arg);
CU_ASSERT (fsm_timeout != NULL)
visited_timeout = 0;
dds_security_fsm_start(fsm_timeout);
int n = 100;
ddsrt_mutex_lock (&g_lock);
while (visited_timeout == 0 && n-- > 0)
{
ddsrt_mutex_unlock (&g_lock);
dds_sleepfor(DDS_MSECS(100));
ddsrt_mutex_lock (&g_lock);
}
ddsrt_mutex_unlock (&g_lock);
dds_security_fsm_free(fsm_timeout);
}

View file

@ -35,9 +35,12 @@
static const char *config =
"${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}"
"<Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
"<Domain id=\"any\">"
" <Tracing><Verbosity>finest</></>"
" <Discovery>"
" <ExternalDomainId>0</ExternalDomainId>"
" <Tag>\\${CYCLONEDDS_PID}</Tag>"
" </Discovery>"
" <Tracing><Verbosity>config</></>"
" <DDSSecurity>"
" <Authentication>"
" <Library finalizeFunction=\"finalize_test_authentication_wrapped\" initFunction=\"init_test_authentication_wrapped\" path=\"" WRAPPERLIB_PATH("dds_security_authentication_wrapper") "\"/>"
@ -68,30 +71,27 @@ static dds_entity_t g_part2_participant = 0;
static void handshake_init(void)
{
/* Domains for pub and sub use a different domain id, but the portgain setting
* in configuration is 0, so that both domains will map to the same port number.
* This allows to create two domains in a single test process. */
char *conf_part1 = ddsrt_expand_envvars(config, DDS_DOMAINID_PART1);
char *conf_part2 = ddsrt_expand_envvars(config, DDS_DOMAINID_PART2);
g_part1_domain = dds_create_domain(DDS_DOMAINID_PART1, conf_part1);
g_part2_domain = dds_create_domain(DDS_DOMAINID_PART2, conf_part2);
dds_free(conf_part1);
dds_free(conf_part2);
char *conf_part1 = ddsrt_expand_envvars_sh (config, DDS_DOMAINID_PART1);
char *conf_part2 = ddsrt_expand_envvars_sh (config, DDS_DOMAINID_PART2);
g_part1_domain = dds_create_domain (DDS_DOMAINID_PART1, conf_part1);
g_part2_domain = dds_create_domain (DDS_DOMAINID_PART2, conf_part2);
dds_free (conf_part1);
dds_free (conf_part2);
CU_ASSERT_FATAL((g_part1_participant = dds_create_participant(DDS_DOMAINID_PART1, NULL, NULL)) > 0);
CU_ASSERT_FATAL((g_part2_participant = dds_create_participant(DDS_DOMAINID_PART2, NULL, NULL)) > 0);
CU_ASSERT_FATAL ((g_part1_participant = dds_create_participant (DDS_DOMAINID_PART1, NULL, NULL)) > 0);
CU_ASSERT_FATAL ((g_part2_participant = dds_create_participant (DDS_DOMAINID_PART2, NULL, NULL)) > 0);
}
static void handshake_fini(void)
{
CU_ASSERT_EQUAL_FATAL(dds_delete(g_part1_participant), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(g_part2_participant), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(g_part1_domain), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(g_part2_domain), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL (dds_delete (g_part1_participant), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL (dds_delete (g_part2_participant), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL (dds_delete (g_part1_domain), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL (dds_delete (g_part2_domain), DDS_RETCODE_OK);
}
CU_Test(ddssec_handshake, happy_day, .init = handshake_init, .fini = handshake_fini)
{
validate_handshake(DDS_DOMAINID_PART1, false, NULL, false, NULL);
validate_handshake(DDS_DOMAINID_PART2, false, NULL, false, NULL);
validate_handshake (DDS_DOMAINID_PART1, false, NULL, false, NULL);
validate_handshake (DDS_DOMAINID_PART2, false, NULL, false, NULL);
}

View file

@ -51,8 +51,11 @@
static const char *config =
"${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}"
"<Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
"<Domain id=\"any\">"
" <Discovery>"
" <ExternalDomainId>0</ExternalDomainId>"
" <Tag>\\${CYCLONEDDS_PID}</Tag>"
" </Discovery>"
" <DDSSecurity>"
" <Authentication>"
" <Library finalizeFunction=\"finalize_authentication\" initFunction=\"init_authentication\" />"
@ -219,12 +222,12 @@ static void test_init(const struct domain_sec_config * domain_config, size_t n_s
{ NULL, NULL, 0 }
};
char *conf_pub = ddsrt_expand_vars (config, &expand_lookup_vars_env, config_vars);
char *conf_pub = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars);
create_dom_pp_pubsub (DDS_DOMAINID_PUB, conf_pub, domain_config, n_pub_domains, n_pub_participants,
g_pub_domains, g_pub_participants, g_pub_publishers, &dds_create_publisher);
dds_free (conf_pub);
char *conf_sub = ddsrt_expand_vars (config, &expand_lookup_vars_env, config_vars);
char *conf_sub = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars);
create_dom_pp_pubsub (DDS_DOMAINID_SUB, conf_sub, domain_config, n_sub_domains, n_sub_participants,
g_sub_domains, g_sub_participants, g_sub_subscribers, &dds_create_subscriber);
dds_free (conf_sub);

View file

@ -1,757 +0,0 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <stdio.h>
#include <stdbool.h>
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/misc.h"
#include "CUnit/CUnit.h"
#include "CUnit/Test.h"
#include "dds/dds.h"
#include "dds__types.h"
#include "dds__entity.h"
#include "dds/security/core/dds_security_fsm.h"
#define CHECK_BIT(var, pos) ((var) & (1<<(pos)))
#define FSM_AUTH_ARG 10
#define DB_TC_PRINT_DEBUG (true)
static dds_entity_t g_participant = 0;
static ddsrt_mutex_t g_lock;
static struct dds_security_fsm_control *g_fsm_control = NULL;
static const dds_duration_t msec100 = DDS_MSECS(100);
//static int fsm_arg = FSM_AUTH_ARG;
#define DO_SIMPLE(name, var, bit) static void name(struct dds_security_fsm *fsm, void *arg) { \
DDSRT_UNUSED_ARG(fsm); \
DDSRT_UNUSED_ARG(arg); \
if (DB_TC_PRINT_DEBUG) \
printf("Transition %s\n", __FUNCTION__); \
ddsrt_mutex_lock(&g_lock); \
visited_##var |= 1u << (bit); \
ddsrt_mutex_unlock(&g_lock); \
}
/**********************************************************************
* Authentication State Machine properties and methods
**********************************************************************/
typedef enum {
VALIDATION_PENDING_RETRY,
VALIDATION_FAILED,
VALIDATION_OK,
VALIDATION_OK_FINAL_MESSAGE,
VALIDATION_PENDING_HANDSHAKE_MESSAGE,
VALIDATION_PENDING_HANDSHAKE_REQUEST,
PluginReturn_MAX
} PluginReturn;
static struct dds_security_fsm *fsm_auth;
static uint32_t visited_auth = 0;
static uint32_t correct_fsm = 0;
static uint32_t correct_arg = 0;
static int validate_remote_identity_first = 1;
static int begin_handshake_reply_first = 1;
static PluginReturn validate_remote_identity(void)
{
if (DB_TC_PRINT_DEBUG) {
printf("validate_remote_identity - %d\n", validate_remote_identity_first);
}
if (validate_remote_identity_first) {
validate_remote_identity_first = 0;
return VALIDATION_PENDING_RETRY;
}
return VALIDATION_PENDING_HANDSHAKE_MESSAGE;
}
static PluginReturn begin_handshake_reply(void)
{
if (DB_TC_PRINT_DEBUG) {
printf("begin_handshake_reply - %d\n", begin_handshake_reply_first);
}
if (begin_handshake_reply_first) {
begin_handshake_reply_first = 0;
return VALIDATION_PENDING_RETRY;
}
return VALIDATION_OK_FINAL_MESSAGE;
}
static PluginReturn get_shared_secret(void)
{
return VALIDATION_OK;
}
/* State actions. */
static void fsm_validate_remote_identity(struct dds_security_fsm *fsm, void *arg)
{
PluginReturn ret;
DDSRT_UNUSED_ARG(arg);
ret = validate_remote_identity();
if (DB_TC_PRINT_DEBUG) {
printf("[%p] State %s (ret %d)\n", fsm, __FUNCTION__, (int) ret);
}
dds_security_fsm_dispatch(fsm, (int32_t) ret, false);
}
static void fsm_begin_handshake_reply(struct dds_security_fsm *fsm, void *arg)
{
PluginReturn ret;
DDSRT_UNUSED_ARG(arg);
ret = begin_handshake_reply();
if (ret == VALIDATION_OK_FINAL_MESSAGE) {
ret = get_shared_secret();
}
if (DB_TC_PRINT_DEBUG) {
printf("[%p] State %s (ret %d)\n", fsm, __FUNCTION__, (int) ret);
}
dds_security_fsm_dispatch(fsm, (int32_t) ret, false);
}
/* A few states from the handshake state-machine. */
static dds_security_fsm_state StateValidateRemoteIdentity = {fsm_validate_remote_identity, 0};
static dds_security_fsm_state StateValRemIdentityRetryWait = {NULL, 100000000};
static dds_security_fsm_state StateHandshakeInitMessageWait = {NULL, 0};
static dds_security_fsm_state StateBeginHandshakeReply = {fsm_begin_handshake_reply, 0};
static dds_security_fsm_state StateBeginHsReplyWait = {NULL, 100000000};
static void a(struct dds_security_fsm *fsm, void *arg)
{
int *fsm_arg;
if (DB_TC_PRINT_DEBUG) {
printf("[%p] Transition %s\n", fsm, __FUNCTION__);
}
ddsrt_mutex_lock (&g_lock);
if (arg != NULL) {
fsm_arg = (int *) arg;
if (*fsm_arg == FSM_AUTH_ARG) {
correct_arg = 1;
} else {
correct_arg = 0;
}
}
if (fsm == fsm_auth) {
correct_fsm = 1;
} else {
correct_fsm = 0;
}
visited_auth |= 1u << 0;
ddsrt_mutex_unlock (&g_lock);
}
DO_SIMPLE(b, auth, 1)
DO_SIMPLE(c, auth, 2)
DO_SIMPLE(d, auth, 3)
DO_SIMPLE(e, auth, 4)
DO_SIMPLE(f, auth, 5)
DO_SIMPLE(g, auth, 6)
DO_SIMPLE(h, auth, 7)
#define SHM_MSG_RECEIVED (PluginReturn_MAX + 1)
/*
* .--.
* |##|--------------------------------------.
* '--' a() v
* .----------------------------------------------------.
* | StateValidateRemoteIdentity |
* |----------------------------------------------------|
* .------>| fsm_validate_remote_identity() |
* | | - dispatch VALIDATION_PENDING_RETRY |
* 100ms| | - dispatch VALIDATION_PENDING_HANDSHAKE_MESSAGE |
* d() | '----------------------------------------------------'
* | VALIDATION_PENDING_RETRY| | VALIDATION_PENDING_HANDSHAKE_MESSAGE
* | b() | | c()
* | | |
* .------------------------------. | | .-------------------------------.
* | StateValRemIdentityRetryWait | | | | StateHandshakeInitMessageWait |
* |------------------------------|<----------' '------>|-------------------------------|
* '------------------------------' '-------------------------------'
* SHM_MSG_RECEIVED |
* e() |
* v
* .----------------------------------------.
* VALIDATION_PENDING_RETRY | StateBeginHandshakeReply |
* f() |----------------------------------------|
* .-------------------------| fsm_begin_handshake_reply() |
* | | - dispatch VALIDATION_PENDING_RETRY |
* v | - dispatch VALIDATION_OK |
* .-----------------------. 100ms '----------------------------------------'
* | StateBeginHsReplyWait | h() ^ VALIDATION_OK |
* |-----------------------|-----------------------' g() |
* '-----------------------' v
* .-.
* '-'
*/
static dds_security_fsm_transition HandshakeTransistions[] = {
{NULL, DDS_SECURITY_FSM_EVENT_AUTO, a, &StateValidateRemoteIdentity}, // NULL state is the start state
{&StateValidateRemoteIdentity, VALIDATION_PENDING_RETRY, b, &StateValRemIdentityRetryWait},
{&StateValidateRemoteIdentity, VALIDATION_PENDING_HANDSHAKE_MESSAGE, c, &StateHandshakeInitMessageWait},
{&StateValRemIdentityRetryWait, DDS_SECURITY_FSM_EVENT_TIMEOUT, d, &StateValidateRemoteIdentity},
{&StateHandshakeInitMessageWait, SHM_MSG_RECEIVED, e, &StateBeginHandshakeReply},
{&StateBeginHandshakeReply, VALIDATION_PENDING_RETRY, f, &StateBeginHsReplyWait},
{&StateBeginHandshakeReply, VALIDATION_OK, g, NULL}, // Reaching NULL means end of state-diagram
{&StateBeginHsReplyWait, DDS_SECURITY_FSM_EVENT_TIMEOUT, h, &StateBeginHandshakeReply}
};
static const uint32_t HandshakeTransistionsSize = sizeof(HandshakeTransistions)/sizeof(HandshakeTransistions[0]);
/**********************************************************************
* Example State Machine properties and methods
**********************************************************************/
typedef enum {
eventX, eventY, eventZ,
} test_events;
static struct dds_security_fsm *fsm_test;
static uint32_t visited_test = 0;
static int do_stuff_counter = 0;
static int do_other_stuff_counter = 0;
DO_SIMPLE(doStart, test, 0)
DO_SIMPLE(doRestart, test, 1)
DO_SIMPLE(doEventStuff, test, 4)
static void doStuff(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(fsm);
DDSRT_UNUSED_ARG(arg);
if (DB_TC_PRINT_DEBUG) {
printf("Transition %s - %d\n", __FUNCTION__, do_stuff_counter);
}
ddsrt_mutex_lock (&g_lock);
visited_test |= 1u << 2;
ddsrt_mutex_unlock (&g_lock);
if (do_stuff_counter < 2) {
dds_security_fsm_dispatch(fsm, eventZ, false);
} else if (do_stuff_counter == 2) {
dds_security_fsm_dispatch(fsm, eventY, false);
}
++do_stuff_counter;
}
static void doOtherStuff(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(fsm);
DDSRT_UNUSED_ARG(arg);
if (DB_TC_PRINT_DEBUG) {
printf("Transition %s - %d\n", __FUNCTION__, do_other_stuff_counter);
}
ddsrt_mutex_lock (&g_lock);
visited_test |= 1u << 3;
ddsrt_mutex_unlock (&g_lock);
if (do_other_stuff_counter == 0) {
dds_security_fsm_dispatch(fsm, DDS_SECURITY_FSM_EVENT_AUTO, false);
}
if (do_other_stuff_counter == 1) {
dds_security_fsm_dispatch(fsm, eventY, false);
} else if (do_other_stuff_counter == 2) {
dds_security_fsm_dispatch(fsm, eventX, false);
}
++do_other_stuff_counter;
}
static dds_security_fsm_state StateA = {doStuff, 0};
static dds_security_fsm_state StateB = {doStuff, 100000000};
static dds_security_fsm_state StateC = {NULL, 0};
static dds_security_fsm_state StateD = {doOtherStuff, 0};
static dds_security_fsm_transition Transitions[] = {
{NULL, DDS_SECURITY_FSM_EVENT_AUTO, doStart, &StateA}, // NULL state is the start state
{&StateA, eventZ, NULL, &StateB},
{&StateA, eventY, doOtherStuff, &StateC},
{&StateB, eventX, NULL, NULL}, // Reaching NULL means end of state-diagram
{&StateB, eventZ, doRestart, &StateA},
{&StateC, DDS_SECURITY_FSM_EVENT_AUTO, doEventStuff, &StateD},
{&StateD, eventY, doEventStuff, &StateD},
{&StateD, eventX, doStuff, NULL}, // Reaching NULL means end of sttimeoutate-diagram
};
static const uint32_t TransitionsSize = sizeof(Transitions)/sizeof(Transitions[0]);
/**********************************************************************
* Timeout State Machine properties and methods
**********************************************************************/
typedef enum {
eventToTimeout, eventToInterupt, eventToEnd,
} timeout_events;
struct fsm_timeout_arg {
int id;
};
static struct dds_security_fsm *fsm_timeout;
static uint32_t visited_timeout = 0;
static uint32_t correct_fsm_timeout = 0;
static uint32_t correct_arg_timeout = 0;
static struct fsm_timeout_arg fsm_arg = { .id = FSM_AUTH_ARG };
DO_SIMPLE(doInterrupt, timeout, 0)
DO_SIMPLE(TimeoutCallback2, timeout, 3)
static void doTimeout(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(arg);
if (DB_TC_PRINT_DEBUG) {
printf("Transition >>>> %s\n", __FUNCTION__);
}
ddsrt_mutex_lock (&g_lock);
visited_timeout |= 1u << 1;
ddsrt_mutex_unlock (&g_lock);
if (DB_TC_PRINT_DEBUG) {
printf("Transition <<<< %s\n", __FUNCTION__);
}
dds_security_fsm_dispatch(fsm, eventToTimeout, false);
}
static void TimeoutCallback(struct dds_security_fsm *fsm, void *arg)
{
struct fsm_timeout_arg *farg = arg;
if (DB_TC_PRINT_DEBUG) {
printf("TimeoutCallback\n");
}
ddsrt_mutex_lock (&g_lock);
visited_timeout |= 1u << 2;
if (farg != NULL) {
if (farg->id == FSM_AUTH_ARG) {
correct_arg_timeout = 1;
} else {
correct_arg_timeout = 0;
}
}
if (fsm == fsm_timeout) {
correct_fsm_timeout = 1;
} else {
correct_fsm_timeout = 0;
}
ddsrt_mutex_unlock (&g_lock);
}
static dds_security_fsm_state StateInitial = {doTimeout, 0};
static dds_security_fsm_state StateWaitTimeout = {NULL, DDS_SECS(4)};
static dds_security_fsm_state StateInterupt = {doInterrupt, 0};
static const dds_security_fsm_transition TimeoutTransitions[] = {
{NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &StateInitial}, // NULL state is the start state
{&StateInitial, eventToTimeout, NULL, &StateWaitTimeout},
{&StateWaitTimeout, DDS_SECURITY_FSM_EVENT_TIMEOUT, NULL, &StateInterupt},
{&StateWaitTimeout, eventToInterupt, NULL, &StateInterupt},
{&StateInterupt, eventToEnd, NULL, NULL}, // Reaching NULL means end of state-diagram
};
static const uint32_t TimeoutTransitionsSize = sizeof(TimeoutTransitions)/sizeof(TimeoutTransitions[0]);
/**********************************************************************
* Parallel Timeout State Machines properties and methods
**********************************************************************/
static struct dds_security_fsm *fsm_timeout1;
static struct dds_security_fsm *fsm_timeout2;
static struct dds_security_fsm *fsm_timeout3;
static dds_time_t time0 = 0;
static dds_time_t time1 = 0;
static dds_time_t time2 = 0;
static dds_time_t time3 = 0;
static void StateParTime1(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(fsm);
DDSRT_UNUSED_ARG(arg);
time1 = dds_time();
}
static void StateParTime2(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(fsm);
DDSRT_UNUSED_ARG(arg);
time2 = dds_time();
}
static void StateParTime3(struct dds_security_fsm *fsm, void *arg)
{
DDSRT_UNUSED_ARG(fsm);
DDSRT_UNUSED_ARG(arg);
time3 = dds_time();
}
static dds_security_fsm_state StateParTimeout1 = {NULL, DDS_SECS(1)};
static dds_security_fsm_state StateParTimeout2 = {NULL, DDS_SECS(2)};
static dds_security_fsm_state StateParTimeout3 = {NULL, DDS_SECS(1)};
static dds_security_fsm_transition ParallelTimeoutTransitions_1[] = {
{NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &StateParTimeout1}, // NULL state is the startfsm_control_thread state
{&StateParTimeout1, DDS_SECURITY_FSM_EVENT_TIMEOUT, &StateParTime1, NULL}, // Reaching NULL means end of state-diagram
};
static const uint32_t ParallelTimeoutTransitionsSize_1 = sizeof(ParallelTimeoutTransitions_1) / sizeof(ParallelTimeoutTransitions_1[0]);
static dds_security_fsm_transition ParallelTimeoutTransitions_2[] = {
{NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &StateParTimeout2}, // NULL state is the start state
{&StateParTimeout2, DDS_SECURITY_FSM_EVENT_TIMEOUT, &StateParTime2, NULL}, // Reaching NULL means end of state-diagram
};
static const uint32_t ParallelTimeoutTransitionsSize_2 = sizeof(ParallelTimeoutTransitions_2) / sizeof(ParallelTimeoutTransitions_2[0]);
static dds_security_fsm_transition ParallelTimeoutTransitions_3[] = {
{NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &StateParTimeout3}, // NULL state is the start state
{&StateParTimeout3, DDS_SECURITY_FSM_EVENT_TIMEOUT, &StateParTime3, NULL}, // Reaching NULL means end of state-diagram
};
static const uint32_t ParallelTimeoutTransitionsSize_3 = sizeof(ParallelTimeoutTransitions_3) / sizeof(ParallelTimeoutTransitions_3[0]);
static void fsm_control_init(void)
{
dds_return_t rc;
struct dds_entity *e;
g_participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL(g_participant > 0);
ddsrt_mutex_init (&g_lock);
rc = dds_entity_pin(g_participant, &e);
CU_ASSERT_FATAL(rc == 0);
g_fsm_control = dds_security_fsm_control_create (&e->m_domain->gv);
CU_ASSERT_FATAL (g_fsm_control != NULL);
dds_entity_unpin (e);
rc = dds_security_fsm_control_start (g_fsm_control, NULL);
CU_ASSERT_FATAL(rc == 0);
}
static void fsm_control_fini(void)
{
dds_security_fsm_control_stop(g_fsm_control);
dds_security_fsm_control_free(g_fsm_control);
ddsrt_mutex_destroy (&g_lock);
dds_delete(g_participant);
}
CU_Test(ddssec_fsm, create, .init = fsm_control_init, .fini = fsm_control_fini)
{
dds_time_t delay30 = DDS_SECS(30);
int timeout;
/*
* Test single running state machine
* Check creation of a single State Machine
*/
fsm_auth = dds_security_fsm_create(g_fsm_control, HandshakeTransistions, HandshakeTransistionsSize, &fsm_arg);
CU_ASSERT_FATAL(fsm_auth != NULL)
// set a delay that doesn't expire. Should be terminate when fsm is freed.
dds_security_fsm_set_timeout(fsm_auth, TimeoutCallback, delay30);
dds_security_fsm_start(fsm_auth);
/**
* Check the result of one running State Machine
*/
// Wait for the last state to occur
timeout = 100; /* 10 sec */
while ((dds_security_fsm_current_state(fsm_auth) != &StateHandshakeInitMessageWait) && (timeout > 0)) {
dds_sleepfor(msec100);
timeout--;
}
CU_ASSERT(timeout > 0);
dds_security_fsm_dispatch(fsm_auth, SHM_MSG_RECEIVED, false);
timeout = 100; /* 10 sec */
while ((dds_security_fsm_current_state(fsm_auth) != NULL) && (timeout > 0)) {
dds_sleepfor(msec100);
timeout--;
}
CU_ASSERT(timeout > 0);
ddsrt_mutex_lock (&g_lock);
CU_ASSERT(visited_auth == 0xff);
ddsrt_mutex_unlock (&g_lock);
/*
* "Check correct callback parameter passing (from fsm to user defined methods) ");
*/
CU_ASSERT(correct_arg && correct_fsm);
dds_security_fsm_free(fsm_auth);
/* Check whether timeout callback has NOT been invoked */
ddsrt_mutex_lock (&g_lock);
CU_ASSERT(visited_timeout == 0);
ddsrt_mutex_unlock (&g_lock);
}
/*
* Test multiple (2) running state machines
*/
CU_Test(ddssec_fsm, multiple, .init = fsm_control_init, .fini = fsm_control_fini)
{
int timeout;
/*Check creation of multiple (2) State Machines*/
validate_remote_identity_first = 0;
begin_handshake_reply_first = 0;
visited_auth = 0;
visited_test = 0;
fsm_auth = dds_security_fsm_create(g_fsm_control, HandshakeTransistions, HandshakeTransistionsSize, NULL);
CU_ASSERT_FATAL(fsm_auth != NULL);
fsm_test = dds_security_fsm_create(g_fsm_control, Transitions, TransitionsSize, NULL);
CU_ASSERT_FATAL(fsm_test != NULL);
dds_security_fsm_start(fsm_auth);
dds_security_fsm_start(fsm_test);
/* Check the results of multiple running State Machines */
/* Wait for the last state to occur */
timeout = 100; /* 10 sec */
while ((dds_security_fsm_current_state(fsm_auth) != &StateHandshakeInitMessageWait) && (timeout > 0)) {
dds_sleepfor(100 * DDS_NSECS_IN_MSEC);
timeout--;
}
CU_ASSERT_FATAL(timeout > 0);
timeout = 100; /* 10 sec */
dds_security_fsm_dispatch(fsm_auth, SHM_MSG_RECEIVED, false);
while ((dds_security_fsm_current_state(fsm_auth) != NULL) && (timeout > 0)) {
dds_sleepfor(100 * DDS_NSECS_IN_MSEC);
timeout--;
}
CU_ASSERT_FATAL(timeout > 0);
// not all bits are set since we're running the state machine a second time
ddsrt_mutex_lock (&g_lock);
CU_ASSERT_FATAL(visited_auth == 0x55);
ddsrt_mutex_unlock (&g_lock);
/* Wait for the last state to occur */
timeout = 100; /* 10 sec */
while ((dds_security_fsm_current_state(fsm_test) != NULL) && timeout > 0) {
dds_sleepfor(100 * DDS_NSECS_IN_MSEC);
timeout--;
}
CU_ASSERT_FATAL(timeout > 0);
ddsrt_mutex_lock (&g_lock);
CU_ASSERT(visited_test == 0x1f);
ddsrt_mutex_unlock (&g_lock);
dds_security_fsm_free(fsm_auth);
dds_security_fsm_free(fsm_test);
}
/**
* Check creation of State Machine for timeout purposes
*/
CU_Test(ddssec_fsm, timeout, .init = fsm_control_init, .fini = fsm_control_fini)
{
dds_time_t delay1 = DDS_SECS(1);
int timeout;
visited_timeout = 0;
/*
* Test timeout monitoring of state machines
*/
fsm_timeout = dds_security_fsm_create(g_fsm_control, TimeoutTransitions, TimeoutTransitionsSize, &fsm_arg);
CU_ASSERT(fsm_timeout != NULL);
dds_security_fsm_set_timeout(fsm_timeout, TimeoutCallback, delay1);
dds_security_fsm_start(fsm_timeout);
/*Check the result of the running State Machine for timeout purposes*/
// Wait for the last state to occur
timeout = 100; /* 10 sec */
ddsrt_mutex_lock (&g_lock);
while (visited_timeout != 0x7 && (timeout > 0)) {
ddsrt_mutex_unlock (&g_lock);
dds_sleepfor(100 * DDS_NSECS_IN_MSEC);
timeout--;
ddsrt_mutex_lock (&g_lock);
}
CU_ASSERT(timeout > 0);
CU_ASSERT(visited_timeout == 0x7);
CU_ASSERT(correct_arg_timeout && correct_fsm_timeout);
ddsrt_mutex_unlock (&g_lock);
dds_security_fsm_free(fsm_timeout);
}
/**
* Check the double global timeout
*/
CU_Test(ddssec_fsm, double_timeout, .init = fsm_control_init, .fini = fsm_control_fini)
{
dds_time_t delay1 = DDS_SECS(1);
dds_time_t delay2 = DDS_SECS(2);
int timeout;
visited_timeout = 0;
fsm_timeout = dds_security_fsm_create(g_fsm_control, TimeoutTransitions, TimeoutTransitionsSize, &fsm_arg);
CU_ASSERT(fsm_timeout != NULL);
fsm_timeout2 = dds_security_fsm_create(g_fsm_control, TimeoutTransitions, TimeoutTransitionsSize, &fsm_arg);
CU_ASSERT(fsm_timeout2 != NULL);
dds_security_fsm_set_timeout(fsm_timeout, TimeoutCallback, delay1);
dds_security_fsm_set_timeout(fsm_timeout2, TimeoutCallback2, delay2);
dds_security_fsm_start(fsm_timeout);
dds_security_fsm_start(fsm_timeout2);
timeout = 100; /* 10 sec */
ddsrt_mutex_lock (&g_lock);
while (visited_timeout != 0xf && (timeout > 0)) {
ddsrt_mutex_unlock (&g_lock);
dds_sleepfor(100 * DDS_NSECS_IN_MSEC);
timeout--;
ddsrt_mutex_lock (&g_lock);
}
CU_ASSERT(visited_timeout == 0xf);
ddsrt_mutex_unlock (&g_lock);
dds_security_fsm_free(fsm_timeout);
dds_security_fsm_free(fsm_timeout2);
}
/**
* Check parallel state timeouts
*/
CU_Test(ddssec_fsm, parallel_timeout, .init = fsm_control_init, .fini = fsm_control_fini)
{
dds_duration_t delta1;
dds_duration_t delta2;
dds_duration_t delta3;
int timeout;
visited_timeout = 0;
fsm_timeout1 = dds_security_fsm_create(g_fsm_control, ParallelTimeoutTransitions_1, ParallelTimeoutTransitionsSize_1, &fsm_arg);
CU_ASSERT_FATAL(fsm_timeout1 != NULL);
fsm_timeout2 = dds_security_fsm_create(g_fsm_control, ParallelTimeoutTransitions_2, ParallelTimeoutTransitionsSize_2, &fsm_arg);
CU_ASSERT_FATAL(fsm_timeout2 != NULL);
fsm_timeout3 = dds_security_fsm_create(g_fsm_control, ParallelTimeoutTransitions_3, ParallelTimeoutTransitionsSize_3, &fsm_arg);
CU_ASSERT_FATAL(fsm_timeout3 != NULL);
time0 = dds_time();
dds_security_fsm_start(fsm_timeout1);
dds_security_fsm_start(fsm_timeout2);
dds_security_fsm_start(fsm_timeout3);
/* Wait for both to end. */
timeout = 300; /* 10 sec */
/* First, they have to be started. */
while (((dds_security_fsm_current_state(fsm_timeout1) == NULL)
|| (dds_security_fsm_current_state(fsm_timeout2) == NULL)
|| (dds_security_fsm_current_state(fsm_timeout3) == NULL)) && (timeout > 0)) {
dds_sleepfor(100 * DDS_NSECS_IN_MSEC);
timeout--;
}
/* Then, they have to have ended. */
while (((dds_security_fsm_current_state(fsm_timeout1) != NULL)
|| (dds_security_fsm_current_state(fsm_timeout2) != NULL)
|| (dds_security_fsm_current_state(fsm_timeout3) != NULL)) && (timeout > 0)) {
dds_sleepfor(100 * DDS_NSECS_IN_MSEC);
timeout--;
}
/*
* There should be about 1 second difference between all times:
* time1 = time0 + 1
* time2 = time0 + 2
* time3 = time0 + 1
*/
delta1 = time1 - time0;
delta2 = time2 - time0;
delta3 = time3 - time0;
printf("Time0 %" PRId64 "\n", time0);
printf("Time1 %" PRId64 "\n", time1);
printf("Time2 %" PRId64 "\n", time2);
printf("Time3 %" PRId64 "\n", time3);
printf("Delta1 %" PRId64 "\n", delta1);
printf("Delta2 %" PRId64 "\n", delta2);
printf("Delta3 %" PRId64 "\n", delta3);
CU_ASSERT(delta1 > 750 * DDS_NSECS_IN_MSEC);
CU_ASSERT(delta1 < 1250 * DDS_NSECS_IN_MSEC);
CU_ASSERT(delta2 > 1750 * DDS_NSECS_IN_MSEC);
CU_ASSERT(delta2 < 2250 * DDS_NSECS_IN_MSEC);
CU_ASSERT(delta3 > 750 * DDS_NSECS_IN_MSEC);
CU_ASSERT(delta3 < 1250 * DDS_NSECS_IN_MSEC);
dds_security_fsm_free(fsm_timeout1);
dds_security_fsm_free(fsm_timeout2);
dds_security_fsm_free(fsm_timeout3);
}
/**
* Delete with event timeout
*/
CU_Test(ddssec_fsm, delete_with_timeout, .init = fsm_control_init, .fini = fsm_control_fini)
{
int timeout;
fsm_timeout = dds_security_fsm_create(g_fsm_control, TimeoutTransitions, TimeoutTransitionsSize, &fsm_arg);
CU_ASSERT (fsm_timeout != NULL)
visited_timeout = 0;
dds_security_fsm_start(fsm_timeout);
/* Wait until we're in the timeout function. */
timeout = 100; /* 10 sec */
ddsrt_mutex_lock (&g_lock);
while ((visited_timeout == 0) && (timeout > 0)) {
ddsrt_mutex_unlock (&g_lock);
dds_sleepfor(100 * DDS_NSECS_IN_MSEC);
timeout--;
ddsrt_mutex_lock (&g_lock);
}
ddsrt_mutex_unlock (&g_lock);
dds_security_fsm_free(fsm_timeout);
}

View file

@ -0,0 +1,374 @@
/*
* Copyright(c) 2019 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <stdio.h>
#include "CUnit/Test.h"
#include "dds/security/core/dds_security_timed_cb.h"
#include "dds/ddsrt/misc.h"
#define SEQ_SIZE (16)
typedef struct
{
struct dds_security_timed_dispatcher_t *d;
dds_security_timed_cb_kind kind;
void *listener;
void *arg;
dds_time_t time;
} test_sequence_data;
static int g_sequence_idx = 0;
static test_sequence_data g_sequence_array[SEQ_SIZE];
static void simple_callback(struct dds_security_timed_dispatcher_t *d, dds_security_timed_cb_kind kind, void *listener, void *arg)
{
DDSRT_UNUSED_ARG(d);
DDSRT_UNUSED_ARG(kind);
DDSRT_UNUSED_ARG(listener);
*((bool *)arg) = !(*((bool *)arg));
}
static int g_order_callback_idx = 0;
static void *g_order_callback[2] = {(void *)NULL, (void *)NULL};
static void order_callback(struct dds_security_timed_dispatcher_t *d, dds_security_timed_cb_kind kind, void *listener, void *arg)
{
DDSRT_UNUSED_ARG(d);
DDSRT_UNUSED_ARG(kind);
DDSRT_UNUSED_ARG(listener);
g_order_callback[g_order_callback_idx] = arg;
g_order_callback_idx++;
}
static void test_callback(struct dds_security_timed_dispatcher_t *d, dds_security_timed_cb_kind kind, void *listener, void *arg)
{
if (g_sequence_idx < SEQ_SIZE)
{
g_sequence_array[g_sequence_idx].d = d;
g_sequence_array[g_sequence_idx].arg = arg;
g_sequence_array[g_sequence_idx].kind = kind;
g_sequence_array[g_sequence_idx].listener = listener;
g_sequence_array[g_sequence_idx].time = dds_time();
}
g_sequence_idx++;
}
CU_Test(ddssec_timed_cb, simple_test)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
static bool test_var = false;
dds_time_t future = dds_time() + DDS_SECS(2);
struct dds_security_timed_dispatcher_t *d1 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
dds_security_timed_dispatcher_add(tcb, d1, simple_callback, future, (void *)&test_var);
dds_security_timed_dispatcher_enable(tcb, d1, (void *)NULL);
CU_ASSERT_FALSE_FATAL(test_var);
dds_sleepfor(DDS_MSECS(500));
CU_ASSERT_FALSE_FATAL(test_var);
dds_sleepfor(DDS_SECS(2));
CU_ASSERT_TRUE_FATAL(test_var);
dds_security_timed_dispatcher_free(tcb, d1);
dds_security_timed_cb_free(tcb);
}
CU_Test(ddssec_timed_cb, simple_order)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
struct dds_security_timed_dispatcher_t *d1 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
dds_time_t future = dds_time() + DDS_MSECS(20), future2 = future;
dds_security_timed_dispatcher_add(tcb, d1, order_callback, future, (void *)1);
dds_security_timed_dispatcher_add(tcb, d1, order_callback, future2, (void *)2);
dds_security_timed_dispatcher_enable(tcb, d1, (void *)&g_order_callback);
dds_sleepfor(DDS_MSECS(10));
dds_security_timed_dispatcher_free(tcb, d1);
CU_ASSERT_EQUAL_FATAL(g_order_callback[0], (void *)1);
CU_ASSERT_EQUAL_FATAL(g_order_callback[1], (void *)2);
dds_security_timed_cb_free(tcb);
}
CU_Test(ddssec_timed_cb, test_enabled_and_disabled)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
static bool test_var = false;
dds_time_t future = dds_time() + DDS_SECS(2);
struct dds_security_timed_dispatcher_t *d1 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
dds_security_timed_dispatcher_add(tcb, d1, simple_callback, future, (void *)&test_var);
dds_security_timed_dispatcher_enable(tcb, d1, (void *)NULL);
CU_ASSERT_FALSE(test_var);
dds_security_timed_dispatcher_disable(tcb, d1);
dds_sleepfor(DDS_MSECS(500));
CU_ASSERT_FALSE(test_var);
dds_sleepfor(DDS_SECS(2));
CU_ASSERT_FALSE(test_var);
dds_security_timed_dispatcher_free(tcb, d1);
dds_security_timed_cb_free(tcb);
}
CU_Test(ddssec_timed_cb, simple_test_with_future)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
static bool test_var = false;
dds_time_t now = dds_time(), future = now + DDS_SECS(2), far_future = now + DDS_SECS(10);
struct dds_security_timed_dispatcher_t *d1 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
dds_security_timed_dispatcher_enable(tcb, d1, (void *)NULL);
dds_security_timed_dispatcher_add(tcb, d1, simple_callback, future, (void *)&test_var);
dds_security_timed_dispatcher_add(tcb, d1, simple_callback, far_future, (void *)&test_var);
CU_ASSERT_FALSE_FATAL(test_var);
dds_sleepfor(DDS_MSECS(500));
CU_ASSERT_FALSE_FATAL(test_var);
dds_sleepfor(DDS_SECS(2));
CU_ASSERT_TRUE_FATAL(test_var);
dds_security_timed_dispatcher_free(tcb, d1);
dds_security_timed_cb_free(tcb);
}
CU_Test(ddssec_timed_cb, test_multiple_dispatchers)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
static bool test_var = false;
dds_time_t now = dds_time(), future = now + DDS_SECS(2), far_future = now + DDS_SECS(10);
struct dds_security_timed_dispatcher_t *d1 = dds_security_timed_dispatcher_new(tcb);
struct dds_security_timed_dispatcher_t *d2 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
dds_security_timed_dispatcher_enable(tcb, d1, (void *)NULL);
dds_security_timed_dispatcher_enable(tcb, d2, (void *)NULL);
dds_security_timed_dispatcher_free(tcb, d2);
dds_security_timed_dispatcher_add(tcb, d1, simple_callback, future, (void *)&test_var);
dds_security_timed_dispatcher_add(tcb, d1, simple_callback, far_future, (void *)&test_var);
CU_ASSERT_FALSE_FATAL(test_var);
dds_sleepfor(DDS_MSECS(500));
CU_ASSERT_FALSE_FATAL(test_var);
dds_sleepfor(DDS_SECS(2));
CU_ASSERT_TRUE_FATAL(test_var);
dds_security_timed_dispatcher_free(tcb, d1);
dds_security_timed_cb_free(tcb);
}
CU_Test(ddssec_timed_cb, test_not_enabled_multiple_dispatchers)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
struct dds_security_timed_dispatcher_t *d1 = dds_security_timed_dispatcher_new(tcb);
struct dds_security_timed_dispatcher_t *d2 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
CU_ASSERT_PTR_NOT_NULL_FATAL(d2);
dds_security_timed_dispatcher_free(tcb, d2);
dds_security_timed_dispatcher_free(tcb, d1);
dds_security_timed_cb_free(tcb);
}
CU_Test(ddssec_timed_cb, test_create_dispatcher)
{
struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new();
struct dds_security_timed_dispatcher_t *d1 = NULL;
struct dds_security_timed_dispatcher_t *d2 = NULL;
struct dds_security_timed_dispatcher_t *d3 = NULL;
struct dds_security_timed_dispatcher_t *d4 = NULL;
struct dds_security_timed_dispatcher_t *d5 = NULL;
dds_time_t now = dds_time();
dds_time_t past = now - DDS_SECS(1);
dds_time_t present = now + DDS_SECS(1);
dds_time_t future = present + DDS_SECS(1);
dds_time_t future2 = future + DDS_SECS(10);
d1 = dds_security_timed_dispatcher_new(tcb);
d2 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d1);
CU_ASSERT_PTR_NOT_NULL_FATAL(d2);
/* The last argument is a sequence number in which
the callbacks are expected to be called. */
dds_security_timed_dispatcher_add(tcb, d1, test_callback, present, (void *)1);
dds_security_timed_dispatcher_add(tcb, d2, test_callback, past, (void *)0);
dds_security_timed_dispatcher_add(tcb, d2, test_callback, present, (void *)2);
dds_security_timed_dispatcher_add(tcb, d1, test_callback, future, (void *)7);
d3 = dds_security_timed_dispatcher_new(tcb);
d4 = dds_security_timed_dispatcher_new(tcb);
d5 = dds_security_timed_dispatcher_new(tcb);
CU_ASSERT_PTR_NOT_NULL_FATAL(d3);
CU_ASSERT_PTR_NOT_NULL_FATAL(d4);
CU_ASSERT_PTR_NOT_NULL_FATAL(d5);
/* The sleeps are added to get the timing between 'present' and 'past' callbacks right. */
dds_sleepfor(DDS_MSECS(600));
dds_security_timed_dispatcher_enable(tcb, d1, (void *)NULL);
dds_security_timed_dispatcher_enable(tcb, d2, (void *)d2);
dds_security_timed_dispatcher_enable(tcb, d3, (void *)NULL);
/* Specifically not enabling d4 and d5. */
dds_sleepfor(DDS_MSECS(600));
/* The last argument is a sequence number in which the callbacks are expected to be called. */
dds_security_timed_dispatcher_add(tcb, d4, test_callback, past, (void *)99);
dds_security_timed_dispatcher_add(tcb, d2, test_callback, future, (void *)8);
dds_security_timed_dispatcher_add(tcb, d3, test_callback, future2, (void *)9);
dds_security_timed_dispatcher_add(tcb, d1, test_callback, past, (void *)3);
dds_security_timed_dispatcher_add(tcb, d1, test_callback, future2, (void *)10);
dds_security_timed_dispatcher_add(tcb, d1, test_callback, present, (void *)4);
dds_security_timed_dispatcher_add(tcb, d2, test_callback, present, (void *)5);
dds_security_timed_dispatcher_add(tcb, d1, test_callback, future, (void *)6);
dds_security_timed_dispatcher_add(tcb, d3, test_callback, future2, (void *)11);
int idx;
int n = 200;
/* Wait for the callbacks to have been triggered. Ignore the ones in the far future. */
while (g_sequence_idx < 8 && n-- > 0)
dds_sleepfor(DDS_MSECS(10));
/* Print and check sequence of triggered callbacks. */
for (idx = 0; idx < g_sequence_idx && idx < SEQ_SIZE; idx++)
{
int seq = (int)(long long)(g_sequence_array[idx].arg);
struct dds_security_timed_dispatcher_t *expected_d;
void *expected_l;
if (seq == 1 || seq == 6 || seq == 3 || seq == 10 || seq == 4 || seq == 7)
{
expected_d = d1;
expected_l = NULL;
}
else if (seq == 0 || seq == 2 || seq == 8 || seq == 5)
{
expected_d = d2;
expected_l = d2;
}
else if (seq == 9)
{
expected_d = d3;
expected_l = NULL;
}
else if (seq == 99)
{
expected_d = d4;
expected_l = NULL;
CU_FAIL_FATAL("Unexpected callback on a disabled dispatcher");
}
else
{
expected_d = NULL;
expected_l = NULL;
CU_FAIL_FATAL(sprintf("Unknown sequence idx received %d", seq));
}
if (seq != idx)
{
/* 6 and 7 order may be mixed since the order is not defined for same time stamp */
if (!((seq == 6 && idx == 7) || (seq == 7 && idx == 6)))
{
CU_FAIL_FATAL(sprintf("Unexpected sequence ordering %d vs %d\n", seq, idx));
}
}
if (seq > 8)
{
CU_FAIL_FATAL(sprintf("Unexpected sequence idx %d of the far future", seq));
}
if (idx > 8)
{
CU_FAIL_FATAL(sprintf("Too many callbacks %d", idx));
}
/* Callback contents checks. */
if (expected_d != NULL)
{
if (g_sequence_array[idx].d != expected_d)
{
CU_FAIL_FATAL(sprintf("Unexpected dispatcher %p vs %p\n", g_sequence_array[idx].d, expected_d));
}
if (g_sequence_array[idx].listener != expected_l)
{
CU_FAIL_FATAL(sprintf("Unexpected listener %p vs %p", g_sequence_array[idx].listener, expected_l));
}
}
/* Callback kind check. */
if (g_sequence_array[idx].kind != DDS_SECURITY_TIMED_CB_KIND_TIMEOUT)
{
CU_FAIL_FATAL(sprintf("Unexpected kind %d vs %d", (int)g_sequence_array[idx].kind, (int)DDS_SECURITY_TIMED_CB_KIND_TIMEOUT));
}
}
if (g_sequence_idx < 8)
{
CU_FAIL_FATAL(sprintf("Received %d callbacks, while 9 are expected", g_sequence_idx + 1));
}
/* Reset callback index to catch the deletion ones. */
g_sequence_idx = 0;
/* Check if deleting succeeds with dispatchers in different states */
if (d1)
dds_security_timed_dispatcher_free(tcb, d1);
if (d2)
dds_security_timed_dispatcher_free(tcb, d2);
if (d3)
dds_security_timed_dispatcher_free(tcb, d3);
if (d4)
dds_security_timed_dispatcher_free(tcb, d4);
if (d5)
dds_security_timed_dispatcher_free(tcb, d5);
/* Wait for the callbacks to have been triggered. Ignore the ones in the far future. */
n = 200;
while (g_sequence_idx < 4 && n-- > 0)
dds_sleepfor(DDS_MSECS(10));
/* Print and check sequence of triggered callbacks. */
for (idx = 0; (idx < g_sequence_idx) && (idx < SEQ_SIZE); idx++)
{
int seq = (int)(long long)(g_sequence_array[idx].arg);
struct dds_security_timed_dispatcher_t *expected_d;
if (seq == 99)
expected_d = d4;
else if (seq == 9 || seq == 11)
expected_d = d3;
else if (seq == 10)
expected_d = d1;
else
{
expected_d = NULL;
CU_FAIL_FATAL(sprintf("Unexpected sequence idx received %d", seq));
}
if (idx > 4)
{
CU_FAIL_FATAL(sprintf("Too many callbacks %d", idx));
}
/* Callback contents checks. */
if (expected_d != NULL)
{
if (g_sequence_array[idx].d != expected_d)
{
CU_FAIL_FATAL(sprintf("Unexpected dispatcher %p vs %p", g_sequence_array[idx].d, expected_d));
}
if (g_sequence_array[idx].listener != NULL)
{
CU_FAIL_FATAL(sprintf("Unexpected listener %p vs NULL", g_sequence_array[idx].listener));
}
}
/* Callback kind check. */
if (g_sequence_array[idx].kind != DDS_SECURITY_TIMED_CB_KIND_DELETE)
{
CU_FAIL_FATAL(sprintf("Unexpected kind %d vs %d", (int)g_sequence_array[idx].kind, (int)DDS_SECURITY_TIMED_CB_KIND_TIMEOUT));
}
}
if (g_sequence_idx < 4)
{
CU_FAIL_FATAL(sprintf("Received %d callbacks, while 3 are expected", g_sequence_idx + 1));
}
dds_security_timed_cb_free(tcb);
}