Add timed callback dispatcher to security core
Dispatchers are added to a custom linked list while each dispatcher owns a fibheap of callbacks that are ordered by expiry timestamp. A seperate fibheap is use for each dispatcher to allow disabling and enabling of each dispatcher. A new and free function is added that creates a timed_cd_data object that is used by every public function. A thread is initialized at object creation instead of using a counter. Add a protection for the terminate flag. Signed-off-by: Joao Rebelo <jrebelo@s2e-systems.com>
This commit is contained in:
parent
a9b9a65e1b
commit
97c3025e54
5 changed files with 1066 additions and 3 deletions
|
@ -15,6 +15,7 @@ PREPEND(srcs_security_core "${CMAKE_CURRENT_LIST_DIR}/src"
|
||||||
dds_security_plugins.c
|
dds_security_plugins.c
|
||||||
shared_secret.c
|
shared_secret.c
|
||||||
dds_security_fsm.c
|
dds_security_fsm.c
|
||||||
|
dds_security_timed_cb.c
|
||||||
)
|
)
|
||||||
|
|
||||||
PREPEND(hdrs_public_security_core "${CMAKE_CURRENT_LIST_DIR}/include/security/core"
|
PREPEND(hdrs_public_security_core "${CMAKE_CURRENT_LIST_DIR}/include/security/core"
|
||||||
|
@ -24,6 +25,7 @@ PREPEND(hdrs_public_security_core "${CMAKE_CURRENT_LIST_DIR}/include/security/co
|
||||||
dds_security_plugins.h
|
dds_security_plugins.h
|
||||||
dds_security_fsm.h
|
dds_security_fsm.h
|
||||||
shared_secret.h
|
shared_secret.h
|
||||||
|
dds_security_timed_cb.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
|
@ -49,10 +51,12 @@ target_include_directories(security_core
|
||||||
)
|
)
|
||||||
#target_link_libraries(security_core PRIVATE ddsrt security_api)
|
#target_link_libraries(security_core PRIVATE ddsrt security_api)
|
||||||
|
|
||||||
|
if(BUILD_TESTING)
|
||||||
|
add_subdirectory(tests)
|
||||||
|
add_subdirectory(tests/plugin_loading)
|
||||||
|
endif()
|
||||||
|
|
||||||
install(
|
install(
|
||||||
DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include/dds/security/core/"
|
DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include/dds/security/core/"
|
||||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/dds/security/core/"
|
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/dds/security/core/"
|
||||||
COMPONENT dev)
|
COMPONENT dev)
|
||||||
|
|
||||||
add_subdirectory(tests)
|
|
||||||
add_subdirectory(tests/plugin_loading)
|
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
/*
|
||||||
|
* Copyright(c) 2006 to 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DDS_SECURITY_TIMED_CALLBACK_H
|
||||||
|
#define DDS_SECURITY_TIMED_CALLBACK_H
|
||||||
|
|
||||||
|
#include "dds/export.h"
|
||||||
|
#include "dds/ddsrt/time.h"
|
||||||
|
|
||||||
|
#if defined (__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dispatcher that will trigger the timed callbacks.
|
||||||
|
*/
|
||||||
|
struct dds_security_timed_dispatcher_t;
|
||||||
|
|
||||||
|
struct dds_security_timed_cb_data_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The callback is triggered by two causes:
|
||||||
|
* 1. The trigger timeout has been reached.
|
||||||
|
* 2. The related dispatcher is being deleted.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
DDS_SECURITY_TIMED_CB_KIND_TIMEOUT,
|
||||||
|
DDS_SECURITY_TIMED_CB_KIND_DELETE
|
||||||
|
} dds_security_timed_cb_kind;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template for the timed callback functions.
|
||||||
|
* It is NOT allowed to call any t_timed_cb API functions from within this
|
||||||
|
* callback context.
|
||||||
|
*
|
||||||
|
* This will be called when the trigger time of the added callback is reached,
|
||||||
|
* or if the related dispatcher is deleted. The latter can be used to clean up
|
||||||
|
* possible callback resources.
|
||||||
|
*
|
||||||
|
* @param d Related dispatcher.
|
||||||
|
* @param kind Triggered by cb timeout or dispatcher deletion.
|
||||||
|
* @param listener Listener that was provided when enabling the related
|
||||||
|
* dispatcher (NULL with a deletion trigger).
|
||||||
|
* @param arg User data, provided when adding a callback to the
|
||||||
|
* related dispatcher.
|
||||||
|
*/
|
||||||
|
typedef void
|
||||||
|
(*dds_security_timed_cb_t) (
|
||||||
|
struct dds_security_timed_dispatcher_t *d,
|
||||||
|
dds_security_timed_cb_kind kind,
|
||||||
|
void *listener,
|
||||||
|
void *arg);
|
||||||
|
|
||||||
|
DDS_EXPORT struct dds_security_timed_cb_data*
|
||||||
|
dds_security_timed_cb_new(void);
|
||||||
|
|
||||||
|
DDS_EXPORT void
|
||||||
|
dds_security_timed_cb_free(
|
||||||
|
struct dds_security_timed_cb_data *dl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new dispatcher for timed callbacks.
|
||||||
|
* The dispatcher is not enabled (see dds_security_timed_dispatcher_enable).
|
||||||
|
*
|
||||||
|
* @return New (disabled) timed callbacks dispatcher.
|
||||||
|
*/
|
||||||
|
DDS_EXPORT struct dds_security_timed_dispatcher_t*
|
||||||
|
dds_security_timed_dispatcher_new(
|
||||||
|
struct dds_security_timed_cb_data *tcb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the given dispatcher.
|
||||||
|
* If the dispatcher contains timed callbacks, then these will be
|
||||||
|
* triggered with DDS_SECURITY_TIMED_CB_KIND_DELETE and then removed. This
|
||||||
|
* is done whether the dispatcher is enabled or not.
|
||||||
|
*
|
||||||
|
* @param d The dispatcher to free.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DDS_EXPORT void
|
||||||
|
dds_security_timed_dispatcher_free(
|
||||||
|
struct dds_security_timed_cb_data *tcb,
|
||||||
|
struct dds_security_timed_dispatcher_t *d);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables a dispatcher for timed callbacks.
|
||||||
|
*
|
||||||
|
* Until a dispatcher is enabled, no DDS_SECURITY_TIMED_CB_KIND_TIMEOUT callbacks will
|
||||||
|
* be triggered.
|
||||||
|
* As soon as it is enabled, possible stored timed callbacks that are in the
|
||||||
|
* past will be triggered at that moment.
|
||||||
|
* Also, from this point on, possible future callbacks will also be triggered
|
||||||
|
* when the appropriate time has been reached.
|
||||||
|
*
|
||||||
|
* A listener argument can be supplied that is returned when the callback
|
||||||
|
* is triggered. The dispatcher doesn't do anything more with it, so it may
|
||||||
|
* be NULL.
|
||||||
|
*
|
||||||
|
* DDS_SECURITY_TIMED_CB_KIND_DELETE callbacks will always be triggered despite the
|
||||||
|
* dispatcher being possibly disabled.
|
||||||
|
*
|
||||||
|
* @param d The dispatcher to enable.
|
||||||
|
* @param listener An object that is returned with the callback.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DDS_EXPORT void
|
||||||
|
dds_security_timed_dispatcher_enable(
|
||||||
|
struct dds_security_timed_cb_data *tcb,
|
||||||
|
struct dds_security_timed_dispatcher_t *d,
|
||||||
|
void *listener);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables a dispatcher for timed callbacks.
|
||||||
|
*
|
||||||
|
* When a dispatcher is disabled (default after creation), it will not
|
||||||
|
* trigger any related callbacks. It will still store them, however, so
|
||||||
|
* that they can be triggered after a (re)enabling.
|
||||||
|
*
|
||||||
|
* This is when the callback is actually triggered by a timeout and thus
|
||||||
|
* its kind is DDS_SECURITY_TIMED_CB_KIND_TIMEOUT. DDS_SECURITY_TIMED_CB_KIND_DELETE callbacks
|
||||||
|
* will always be triggered despite the dispatcher being possibly disabled.
|
||||||
|
*
|
||||||
|
* @param d The dispatcher to disable.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DDS_EXPORT void
|
||||||
|
dds_security_timed_dispatcher_disable(
|
||||||
|
struct dds_security_timed_cb_data *tcb,
|
||||||
|
struct dds_security_timed_dispatcher_t *d);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a timed callback to a dispatcher.
|
||||||
|
*
|
||||||
|
* The given callback will be triggered with DDS_SECURITY_TIMED_CB_KIND_TIMEOUT when:
|
||||||
|
* 1. The dispatcher is enabled and
|
||||||
|
* 2. The trigger_time has been reached.
|
||||||
|
*
|
||||||
|
* If the trigger_time lays in the past, then the callback is still added.
|
||||||
|
* When the dispatcher is already enabled, it will trigger this 'past'
|
||||||
|
* callback immediately. Otherwise, the 'past' callback will be triggered
|
||||||
|
* at the moment that the dispatcher is enabled.
|
||||||
|
*
|
||||||
|
* The given callback will be triggered with DDS_SECURITY_TIMED_CB_KIND_DELETE when:
|
||||||
|
* 1. The related dispatcher is deleted (ignoring enable/disable).
|
||||||
|
*
|
||||||
|
* This is done so that possible related callback resources can be freed.
|
||||||
|
*
|
||||||
|
* @param d The dispatcher to add the callback to.
|
||||||
|
* @param cb The actual callback function.
|
||||||
|
* @param trigger_time A wall-clock time of when to trigger the callback.
|
||||||
|
* @param arg User data that is provided with the callback.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DDS_EXPORT void
|
||||||
|
dds_security_timed_dispatcher_add(
|
||||||
|
struct dds_security_timed_cb_data *tcb,
|
||||||
|
struct dds_security_timed_dispatcher_t *d,
|
||||||
|
dds_security_timed_cb_t cb,
|
||||||
|
dds_time_t trigger_time,
|
||||||
|
void *arg);
|
||||||
|
|
||||||
|
#if defined (__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* DDS_SECURITY_TIMED_CALLBACK_H */
|
329
src/security/core/src/dds_security_timed_cb.c
Normal file
329
src/security/core/src/dds_security_timed_cb.c
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
/*
|
||||||
|
* Copyright(c) 2006 to 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 <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "dds/ddsrt/atomics.h"
|
||||||
|
#include "dds/ddsrt/heap.h"
|
||||||
|
#include "dds/ddsrt/log.h"
|
||||||
|
#include "dds/ddsrt/sync.h"
|
||||||
|
#include "dds/ddsrt/threads.h"
|
||||||
|
#include "dds/ddsrt/time.h"
|
||||||
|
#include "dds/ddsrt/fibheap.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "dds/security/core/dds_security_timed_cb.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct dds_security_timed_dispatcher_t
|
||||||
|
{
|
||||||
|
bool active;
|
||||||
|
void *listener;
|
||||||
|
ddsrt_fibheap_t events;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct list_dispatcher_t
|
||||||
|
{
|
||||||
|
struct list_dispatcher_t *next;
|
||||||
|
struct dds_security_timed_dispatcher_t *dispatcher;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct event_t
|
||||||
|
{
|
||||||
|
ddsrt_fibheap_node_t heapnode;
|
||||||
|
dds_security_timed_cb_t callback;
|
||||||
|
dds_time_t trigger_time;
|
||||||
|
void *arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int compare_timed_cb_trigger_time(const void *va, const void *vb);
|
||||||
|
static const ddsrt_fibheap_def_t timed_cb_queue_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof(struct event_t, heapnode), compare_timed_cb_trigger_time);
|
||||||
|
|
||||||
|
static int compare_timed_cb_trigger_time(const void *va, const void *vb)
|
||||||
|
{
|
||||||
|
const struct event_t *a = va;
|
||||||
|
const struct event_t *b = vb;
|
||||||
|
return (a->trigger_time == b->trigger_time) ? 0 : (a->trigger_time < b->trigger_time) ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dds_security_timed_cb_data {
|
||||||
|
ddsrt_mutex_t lock;
|
||||||
|
ddsrt_cond_t cond;
|
||||||
|
struct list_dispatcher_t *first_dispatcher_node;
|
||||||
|
ddsrt_thread_t thread;
|
||||||
|
bool terminate;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static uint32_t timed_dispatcher_thread(
|
||||||
|
void *tcbv)
|
||||||
|
{
|
||||||
|
struct list_dispatcher_t *dispatcher_node;
|
||||||
|
struct event_t *event;
|
||||||
|
dds_duration_t timeout;
|
||||||
|
dds_duration_t remain_time;
|
||||||
|
struct dds_security_timed_cb_data *tcb = (struct dds_security_timed_cb_data *)tcbv;
|
||||||
|
|
||||||
|
ddsrt_mutex_lock(&tcb->lock);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
remain_time = DDS_INFINITY;
|
||||||
|
for (dispatcher_node = tcb->first_dispatcher_node; dispatcher_node != NULL; dispatcher_node = dispatcher_node->next)
|
||||||
|
{
|
||||||
|
/* Just some sanity checks. */
|
||||||
|
assert(dispatcher_node->dispatcher);
|
||||||
|
if (dispatcher_node->dispatcher->active)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
timeout = DDS_INFINITY;
|
||||||
|
event = ddsrt_fibheap_min(&timed_cb_queue_fhdef, &dispatcher_node->dispatcher->events);
|
||||||
|
if (event)
|
||||||
|
{
|
||||||
|
/* Just some sanity checks. */
|
||||||
|
assert(event->callback);
|
||||||
|
/* Determine the trigger timeout of this callback. */
|
||||||
|
timeout = event->trigger_time - dds_time();
|
||||||
|
if (timeout <= 0)
|
||||||
|
{
|
||||||
|
/* Trigger callback when related dispatcher is active. */
|
||||||
|
event->callback(dispatcher_node->dispatcher,
|
||||||
|
DDS_SECURITY_TIMED_CB_KIND_TIMEOUT,
|
||||||
|
dispatcher_node->dispatcher->listener,
|
||||||
|
event->arg);
|
||||||
|
|
||||||
|
/* Remove handled event from queue, continue with next. */
|
||||||
|
ddsrt_fibheap_delete(&timed_cb_queue_fhdef, &dispatcher_node->dispatcher->events, event);
|
||||||
|
ddsrt_free(event);
|
||||||
|
}
|
||||||
|
else if (timeout < remain_time)
|
||||||
|
{
|
||||||
|
remain_time = timeout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (timeout < 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// tcb->cond condition may be triggered before this thread runs and causes
|
||||||
|
// this waitfor to wait infinity, hence the check of the tcb->terminate
|
||||||
|
if (((remain_time > 0) || (remain_time == DDS_INFINITY)) && !tcb->terminate)
|
||||||
|
{
|
||||||
|
/* Wait for new event, timeout or the end. */
|
||||||
|
(void)ddsrt_cond_waitfor(&tcb->cond, &tcb->lock, remain_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (!tcb->terminate);
|
||||||
|
|
||||||
|
ddsrt_mutex_unlock(&tcb->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dds_security_timed_cb_data*
|
||||||
|
dds_security_timed_cb_new()
|
||||||
|
{
|
||||||
|
struct dds_security_timed_cb_data *tcb = ddsrt_malloc(sizeof(*tcb));
|
||||||
|
dds_return_t osres;
|
||||||
|
ddsrt_threadattr_t attr;
|
||||||
|
|
||||||
|
ddsrt_mutex_init(&tcb->lock);
|
||||||
|
ddsrt_cond_init(&tcb->cond);
|
||||||
|
tcb->first_dispatcher_node = NULL;
|
||||||
|
tcb->terminate = false;
|
||||||
|
|
||||||
|
ddsrt_threadattr_init(&attr);
|
||||||
|
osres = ddsrt_thread_create(&tcb->thread, "security_dispatcher", &attr, timed_dispatcher_thread, (void*)tcb);
|
||||||
|
if (osres != DDS_RETCODE_OK)
|
||||||
|
{
|
||||||
|
DDS_FATAL("Cannot create thread security_dispatcher");
|
||||||
|
}
|
||||||
|
|
||||||
|
return tcb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dds_security_timed_cb_free(
|
||||||
|
struct dds_security_timed_cb_data *tcb)
|
||||||
|
{
|
||||||
|
ddsrt_mutex_lock(&tcb->lock);
|
||||||
|
tcb->terminate = true;
|
||||||
|
ddsrt_mutex_unlock(&tcb->lock);
|
||||||
|
ddsrt_cond_signal(&tcb->cond);
|
||||||
|
ddsrt_thread_join(tcb->thread, NULL);
|
||||||
|
|
||||||
|
ddsrt_cond_destroy(&tcb->cond);
|
||||||
|
ddsrt_mutex_destroy(&tcb->lock);
|
||||||
|
ddsrt_free(tcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct dds_security_timed_dispatcher_t*
|
||||||
|
dds_security_timed_dispatcher_new(
|
||||||
|
struct dds_security_timed_cb_data *tcb)
|
||||||
|
{
|
||||||
|
struct dds_security_timed_dispatcher_t *d;
|
||||||
|
struct list_dispatcher_t *dispatcher_node_new;
|
||||||
|
struct list_dispatcher_t *dispatcher_node_wrk;
|
||||||
|
|
||||||
|
/* New dispatcher. */
|
||||||
|
d = ddsrt_malloc(sizeof(struct dds_security_timed_dispatcher_t));
|
||||||
|
memset(d, 0, sizeof(struct dds_security_timed_dispatcher_t));
|
||||||
|
|
||||||
|
ddsrt_fibheap_init(&timed_cb_queue_fhdef, &d->events);
|
||||||
|
|
||||||
|
dispatcher_node_new = ddsrt_malloc(sizeof(struct list_dispatcher_t));
|
||||||
|
memset(dispatcher_node_new, 0, sizeof(struct list_dispatcher_t));
|
||||||
|
dispatcher_node_new->dispatcher = d;
|
||||||
|
|
||||||
|
ddsrt_mutex_lock(&tcb->lock);
|
||||||
|
|
||||||
|
/* Append to list */
|
||||||
|
if (tcb->first_dispatcher_node) {
|
||||||
|
struct list_dispatcher_t *last = NULL;
|
||||||
|
for (dispatcher_node_wrk = tcb->first_dispatcher_node; dispatcher_node_wrk != NULL; dispatcher_node_wrk = dispatcher_node_wrk->next) {
|
||||||
|
last = dispatcher_node_wrk;
|
||||||
|
}
|
||||||
|
last->next = dispatcher_node_new;
|
||||||
|
} else {
|
||||||
|
/* This new event is the first one. */
|
||||||
|
tcb->first_dispatcher_node = dispatcher_node_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
ddsrt_mutex_unlock(&tcb->lock);
|
||||||
|
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dds_security_timed_dispatcher_free(
|
||||||
|
struct dds_security_timed_cb_data *tcb,
|
||||||
|
struct dds_security_timed_dispatcher_t *d)
|
||||||
|
{
|
||||||
|
struct event_t *event;
|
||||||
|
struct list_dispatcher_t *dispatcher_node;
|
||||||
|
struct list_dispatcher_t *dispatcher_node_prev;
|
||||||
|
|
||||||
|
assert(d);
|
||||||
|
|
||||||
|
/* Remove related events from queue. */
|
||||||
|
ddsrt_mutex_lock(&tcb->lock);
|
||||||
|
|
||||||
|
while((event = ddsrt_fibheap_extract_min(&timed_cb_queue_fhdef, &d->events)) != NULL)
|
||||||
|
{
|
||||||
|
event->callback(d, DDS_SECURITY_TIMED_CB_KIND_DELETE, NULL, event->arg);
|
||||||
|
ddsrt_free(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove dispatcher from list */
|
||||||
|
dispatcher_node_prev = NULL;
|
||||||
|
for (dispatcher_node = tcb->first_dispatcher_node; dispatcher_node != NULL; dispatcher_node = dispatcher_node->next)
|
||||||
|
{
|
||||||
|
if (dispatcher_node->dispatcher == d)
|
||||||
|
{
|
||||||
|
/* remove element */
|
||||||
|
if (dispatcher_node_prev != NULL)
|
||||||
|
{
|
||||||
|
dispatcher_node_prev->next = dispatcher_node->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tcb->first_dispatcher_node = dispatcher_node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
ddsrt_free(dispatcher_node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dispatcher_node_prev = dispatcher_node;
|
||||||
|
}
|
||||||
|
/* Free this dispatcher. */
|
||||||
|
ddsrt_free(d);
|
||||||
|
|
||||||
|
ddsrt_mutex_unlock(&tcb->lock);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
dds_security_timed_dispatcher_enable(
|
||||||
|
struct dds_security_timed_cb_data *tcb,
|
||||||
|
struct dds_security_timed_dispatcher_t *d,
|
||||||
|
void *listener)
|
||||||
|
{
|
||||||
|
assert(d);
|
||||||
|
assert(!(d->active));
|
||||||
|
|
||||||
|
ddsrt_mutex_lock(&tcb->lock);
|
||||||
|
|
||||||
|
/* Remember possible listener and activate. */
|
||||||
|
d->listener = listener;
|
||||||
|
d->active = true;
|
||||||
|
|
||||||
|
/* Start thread when not running, otherwise wake it up to
|
||||||
|
* trigger callbacks that were (possibly) previously added. */
|
||||||
|
ddsrt_cond_signal(&tcb->cond);
|
||||||
|
|
||||||
|
ddsrt_mutex_unlock(&tcb->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
dds_security_timed_dispatcher_disable(
|
||||||
|
struct dds_security_timed_cb_data *tcb,
|
||||||
|
struct dds_security_timed_dispatcher_t *d)
|
||||||
|
{
|
||||||
|
assert(d);
|
||||||
|
assert(d->active);
|
||||||
|
|
||||||
|
ddsrt_mutex_lock(&tcb->lock);
|
||||||
|
|
||||||
|
/* Forget listener and deactivate. */
|
||||||
|
d->listener = NULL;
|
||||||
|
d->active = false;
|
||||||
|
|
||||||
|
ddsrt_mutex_unlock(&tcb->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
dds_security_timed_dispatcher_add(
|
||||||
|
struct dds_security_timed_cb_data *tcb,
|
||||||
|
struct dds_security_timed_dispatcher_t *d,
|
||||||
|
dds_security_timed_cb_t cb,
|
||||||
|
dds_time_t trigger_time,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
struct event_t *event_new;
|
||||||
|
|
||||||
|
assert(d);
|
||||||
|
assert(cb);
|
||||||
|
|
||||||
|
/* Create event. */
|
||||||
|
event_new = ddsrt_malloc(sizeof(struct event_t));
|
||||||
|
memset(event_new, 0, sizeof(struct event_t));
|
||||||
|
event_new->trigger_time = trigger_time;
|
||||||
|
event_new->callback = cb;
|
||||||
|
event_new->arg = arg;
|
||||||
|
|
||||||
|
/* Insert event based on trigger_time. */
|
||||||
|
ddsrt_mutex_lock(&tcb->lock);
|
||||||
|
ddsrt_fibheap_insert(&timed_cb_queue_fhdef, &d->events, event_new);
|
||||||
|
ddsrt_mutex_unlock(&tcb->lock);
|
||||||
|
|
||||||
|
/* Wake up thread (if it's running). */
|
||||||
|
ddsrt_cond_signal(&tcb->cond);
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ include (CUnit)
|
||||||
|
|
||||||
set(security_core_test_sources
|
set(security_core_test_sources
|
||||||
"tc_fsm.c"
|
"tc_fsm.c"
|
||||||
|
"dds_security_core.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_definitions(-DDDSI_INCLUDE_SECURITY)
|
add_definitions(-DDDSI_INCLUDE_SECURITY)
|
||||||
|
|
546
src/security/core/tests/dds_security_core.c
Normal file
546
src/security/core/tests/dds_security_core.c
Normal file
|
@ -0,0 +1,546 @@
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue