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
 | 
			
		||||
    shared_secret.c
 | 
			
		||||
    dds_security_fsm.c
 | 
			
		||||
    dds_security_timed_cb.c
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
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_fsm.h
 | 
			
		||||
    shared_secret.h
 | 
			
		||||
    dds_security_timed_cb.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
if(NOT WIN32)
 | 
			
		||||
| 
						 | 
				
			
			@ -49,10 +51,12 @@ target_include_directories(security_core
 | 
			
		|||
)
 | 
			
		||||
#target_link_libraries(security_core PRIVATE ddsrt security_api)
 | 
			
		||||
 | 
			
		||||
if(BUILD_TESTING)
 | 
			
		||||
  add_subdirectory(tests)
 | 
			
		||||
  add_subdirectory(tests/plugin_loading)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
install(
 | 
			
		||||
  DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include/dds/security/core/"
 | 
			
		||||
  DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/dds/security/core/"
 | 
			
		||||
  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
 | 
			
		||||
    "tc_fsm.c"
 | 
			
		||||
    "dds_security_core.c"
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
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