diff --git a/docs/manual/options.md b/docs/manual/options.md index f875c77..85ae1eb 100644 --- a/docs/manual/options.md +++ b/docs/manual/options.md @@ -1994,6 +1994,8 @@ threads exist: * tev: general timed-event handling, retransmits and discovery; +* fsm: finite state machine thread for handling security handshake; + * xmit.CHAN: transmit thread for channel CHAN; * dq.CHAN: delivery thread for channel CHAN; diff --git a/etc/cyclonedds.rnc b/etc/cyclonedds.rnc index eac2679..9f03f62 100644 --- a/etc/cyclonedds.rnc +++ b/etc/cyclonedds.rnc @@ -1609,6 +1609,9 @@ for discovery;
  • tev: general timed-event handling, retransmits and discovery;
  • +
  • fsm: finite state machine thread for handling security +handshake;
  • +
  • xmit.CHAN: transmit thread for channel CHAN;
  • dq.CHAN: delivery thread for channel CHAN;
  • diff --git a/etc/cyclonedds.xsd b/etc/cyclonedds.xsd index 8821495..d0d21dd 100644 --- a/etc/cyclonedds.xsd +++ b/etc/cyclonedds.xsd @@ -2133,6 +2133,9 @@ for discovery;</li> <li><i>tev</i>: general timed-event handling, retransmits and discovery;</li> +<li><i>fsm</i>: finite state machine thread for handling security +handshake;</li> + <li><i>xmit.CHAN</i>: transmit thread for channel CHAN;</li> <li><i>dq.CHAN</i>: delivery thread for channel CHAN;</li> diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c index a419f93..53533b0 100644 --- a/src/core/ddsi/src/q_config.c +++ b/src/core/ddsi/src/q_config.c @@ -531,6 +531,7 @@ static const struct cfgelem thread_properties_cfgattrs[] = {
  • dq.builtins: delivery thread for DDSI-builtin data, primarily for discovery;
  • \n\
  • lease: DDSI liveliness monitoring;
  • \n\
  • tev: general timed-event handling, retransmits and discovery;
  • \n\ +
  • fsm: finite state machine thread for handling security handshake;
  • \n\
  • xmit.CHAN: transmit thread for channel CHAN;
  • \n\
  • dq.CHAN: delivery thread for channel CHAN;
  • \n\
  • tev.CHAN: timed-even thread for channel CHAN.
  • ") }, diff --git a/src/core/ddsi/src/q_init.c b/src/core/ddsi/src/q_init.c index 498e069..7765f59 100644 --- a/src/core/ddsi/src/q_init.c +++ b/src/core/ddsi/src/q_init.c @@ -397,10 +397,10 @@ static int known_channel_p (const struct q_globals *gv, const char *name) static int check_thread_properties (const struct q_globals *gv) { #ifdef DDSI_INCLUDE_NETWORK_CHANNELS - static const char *fixed[] = { "recv", "tev", "gc", "lease", "dq.builtins", "debmon", NULL }; + static const char *fixed[] = { "recv", "tev", "gc", "lease", "dq.builtins", "debmon", "fsm", NULL }; static const char *chanprefix[] = { "xmit.", "tev.","dq.",NULL }; #else - static const char *fixed[] = { "recv", "tev", "gc", "lease", "dq.builtins", "xmit.user", "dq.user", "debmon", NULL }; + static const char *fixed[] = { "recv", "tev", "gc", "lease", "dq.builtins", "xmit.user", "dq.user", "debmon", "fsm", NULL }; #endif const struct config_thread_properties_listelem *e; int ok = 1, i; diff --git a/src/security/core/CMakeLists.txt b/src/security/core/CMakeLists.txt index b0701e9..836bc70 100644 --- a/src/security/core/CMakeLists.txt +++ b/src/security/core/CMakeLists.txt @@ -55,3 +55,4 @@ install( COMPONENT dev) add_subdirectory(tests) +add_subdirectory(tests/plugin_loading) diff --git a/src/security/core/include/dds/security/core/dds_security_fsm.h b/src/security/core/include/dds/security/core/dds_security_fsm.h index db6374a..198c1c4 100644 --- a/src/security/core/include/dds/security/core/dds_security_fsm.h +++ b/src/security/core/include/dds/security/core/dds_security_fsm.h @@ -14,14 +14,18 @@ #define DDS_SECURITY_FSM_H #include "dds/ddsrt/time.h" -#include "dds/ddsrt/threads.h" +#include "dds/ddsi/q_globals.h" #if defined (__cplusplus) extern "C" { #endif -#define DDS_SECURITY_FSM_EVENT_AUTO (-1) -#define DDS_SECURITY_FSM_EVENT_TIMEOUT (-2) +#define DDS_SECURITY_FSM_EVENT_AUTO (-1) +#define DDS_SECURITY_FSM_EVENT_TIMEOUT (-2) +#define DDS_SECURITY_FSM_EVENT_DELETE (-3) + +struct dds_security_fsm; +struct dds_security_fsm_control; typedef enum { DDS_SECURITY_FSM_DEBUG_ACT_DISPATCH, @@ -29,13 +33,6 @@ typedef enum { DDS_SECURITY_FSM_DEBUG_ACT_HANDLING } DDS_SECURITY_FSM_DEBUG_ACT; -struct dds_security_fsm; -struct dds_security_fsm_context; - -typedef ddsrt_thread_t (*dds_security_fsm_thread_create_func)(const char *name, ddsrt_thread_routine_t f, void *arg); - -typedef void (*dds_security_fsm_thread_destroy_func)( ddsrt_thread_t tid); - /** * Template for user-defined state methods. * It is allowed to call dds_security_fsm_dispatch() from within a dispatch function. @@ -62,8 +59,7 @@ typedef struct dds_security_fsm_state { * It is not allowed to call any fsm API functions from within this * debug callback. */ -typedef void (*dds_security_fsm_debug)(struct dds_security_fsm *fsm, DDS_SECURITY_FSM_DEBUG_ACT act, - const dds_security_fsm_state *current, int event_id, void *arg); +typedef void (*dds_security_fsm_debug)(struct dds_security_fsm *fsm, DDS_SECURITY_FSM_DEBUG_ACT act, const dds_security_fsm_state *current, int event_id, void *arg); /** * Transition definitions @@ -80,34 +76,6 @@ typedef struct dds_security_fsm_transition { const dds_security_fsm_state *end; } dds_security_fsm_transition; -/** - * Create a new fsm context - * Creates an fsm context. The fsm context manages the global state of the fsm's created within - * this context. The fsm context uses a number of threads to control the state machined allocated - * to this context. A thread create callback has to be provided to created the threads in the - * context of the caller. - * - * @param thr_create_func a callback function used to created the threads used to manage - * the allocated state machines - * - * @return Returns the new fsm context on success. Null on failure. - */ -DDS_EXPORT struct dds_security_fsm_context * -dds_security_fsm_context_create( dds_security_fsm_thread_create_func thr_create_func); - -/** - * Destroys a fsm context - * The function clears the fsm context and stops the associated threads. The thread destroy - * function is called to allow the caller to free resources associated with the threads and - * to wait for the threads to exit. - * - * @param context the context to be destroyed - * @param thr_destroy_func a callback function used to wait a thread to terminate - * the allocated state machine - */ -DDS_EXPORT void -dds_security_fsm_context_destroy(struct dds_security_fsm_context *context, - dds_security_fsm_thread_destroy_func thr_destroy_func); /** * Create a new fsm @@ -121,8 +89,8 @@ dds_security_fsm_context_destroy(struct dds_security_fsm_context *context, * @return Returns the new created state machine on success. Null on failure. */ DDS_EXPORT struct dds_security_fsm * -dds_security_fsm_create(struct dds_security_fsm_context *context, - const dds_security_fsm_transition *transitions, int size, void *arg); +dds_security_fsm_create(struct dds_security_fsm_control *control, const dds_security_fsm_transition *transitions, uint32_t size, void *arg); + /** * Start a fsm @@ -164,20 +132,10 @@ dds_security_fsm_set_debug(struct dds_security_fsm *fsm, dds_security_fsm_debug * * @param fsm The state machine * @param event_id Indicate where to transisition to (outcome of current state) + * @param prio Indicates if the event has to be scheduled with priority. */ DDS_EXPORT void -dds_security_fsm_dispatch(struct dds_security_fsm *fsm, int32_t event_id); - -/** - * Dispatches the next event with priority - * Assignment for the state machine to transisiton to the next state. - * This event will be placed at the top of the event list. - * - * @param fsm The state machine - * @param event_id Indicate where to transisition to (outcome of current state) - */ -DDS_EXPORT void -dds_security_fsm_dispatch_direct(struct dds_security_fsm *fsm, int32_t event_id); +dds_security_fsm_dispatch(struct dds_security_fsm *fsm, int32_t event_id, bool prio); /** * Retrieve the current state of a given state machine @@ -190,17 +148,7 @@ DDS_EXPORT const dds_security_fsm_state* dds_security_fsm_current_state(struct dds_security_fsm *fsm); /** - * Clean the given state machine - * Cleaning up the given state machine. This will abort all timeouts for - * this state machine and remove all events from the internals. - * - * @param fsm The state machine to clean. - */ -DDS_EXPORT void -dds_security_fsm_cleanup(struct dds_security_fsm *fsm); - -/** - * Freeing the state machine. + * Free the state machine. * Stops all running timeouts and events and cleaning all memory * related to this machine. * @@ -212,11 +160,51 @@ dds_security_fsm_cleanup(struct dds_security_fsm *fsm); * not block. It will garbage collect when the event has been * handled. * - * @param fsm The state machine to free + * @param fsm The state machine to be removed */ -DDS_EXPORT void /* Implicit cleanup. */ +DDS_EXPORT void dds_security_fsm_free(struct dds_security_fsm *fsm); +/** + * Create a new fsm control context, + * The fsm control context manages the global state of the fsm's created within + * this context. The fsm control a thread to control the state machined allocated + * to this control. + * + * @param gv The global settings. + * + * @return Returns the new fsm control on success. Null on failure. + */ +DDS_EXPORT struct dds_security_fsm_control * +dds_security_fsm_control_create (struct q_globals *gv); + +/** + * Frees the fsm control and the allocated fsm's. + * A precondition is that the fsm control is stopped. + * + * @param control The fsm control to be freed. + */ +DDS_EXPORT void +dds_security_fsm_control_free(struct dds_security_fsm_control *control); + +/** + * Starts the thread that handles the events and timeouts associated + * with the fsm that are managed by this fsm control. + * + * @param control The fsm control to be started. + */ +DDS_EXPORT dds_return_t +dds_security_fsm_control_start (struct dds_security_fsm_control *control, const char *name); + +/** + * Stops the thread that handles the events and timeouts. + * + * @param control The fsm control to be started. + */ +DDS_EXPORT void +dds_security_fsm_control_stop(struct dds_security_fsm_control *control); + + #if defined (__cplusplus) } #endif diff --git a/src/security/core/src/dds_security_fsm.c b/src/security/core/src/dds_security_fsm.c index 220b017..4fa9d8e 100644 --- a/src/security/core/src/dds_security_fsm.c +++ b/src/security/core/src/dds_security_fsm.c @@ -9,91 +9,87 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ - #include #include -#include "dds/security/core/dds_security_fsm.h" -#include "dds/ddsrt/threads.h" +#include + #include "dds/ddsrt/sync.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/atomics.h" #include "dds/ddsrt/retcode.h" #include "dds/ddsrt/time.h" #include "dds/ddsrt/timeconv.h" -#include +#include "dds/ddsrt/fibheap.h" +#include "dds/ddsi/q_thread.h" +#include "dds/security/core/dds_security_fsm.h" -typedef struct dds_security_fsm { - const dds_security_fsm_transition *transitions; - int size; - void *arg; - const dds_security_fsm_state *current; - dds_time_t current_state_endtime; - ddsrt_atomic_uint32_t ref_cnt; - dds_security_fsm_debug debug_func; - struct dds_security_fsm_context *context; - struct dds_security_fsm *next; - struct dds_security_fsm *prev; -} dds_security_fsm; - -typedef struct fsm_event { +struct fsm_event +{ struct dds_security_fsm *fsm; int event_id; struct fsm_event *next; struct fsm_event *prev; -} fsm_event; +}; -typedef struct fsm_state_timeout { +typedef enum fsm_timeout_kind { + FSM_TIMEOUT_STATE, + FSM_TIMEOUT_OVERALL +} fsm_timeout_kind_t; + +struct fsm_timer_event +{ + ddsrt_fibheap_node_t heapnode; struct dds_security_fsm *fsm; + fsm_timeout_kind_t kind; dds_time_t endtime; -} fsm_state_timeout; +}; -typedef struct fsm_overall_timeout { - struct dds_security_fsm *fsm; - dds_time_t endtime; - dds_security_fsm_action func; - struct fsm_overall_timeout *next; - struct fsm_overall_timeout *prev; -} fsm_overall_timeout; +struct dds_security_fsm +{ + struct dds_security_fsm *next_fsm; + struct dds_security_fsm *prev_fsm; + bool active; + struct dds_security_fsm_control *control; + const dds_security_fsm_transition *transitions; + uint32_t size; + void *arg; + const dds_security_fsm_state *current; + struct fsm_timer_event state_timeout_event; + struct fsm_timer_event overall_timeout_event; + dds_security_fsm_action overall_timeout_action; + dds_security_fsm_debug debug_func; +}; -typedef struct dds_security_fsm_context { - ddsrt_thread_t fsm_tid; - ddsrt_thread_t fsm_timeout_tid; - bool fsm_teardown; - fsm_event *fsm_queue; - fsm_overall_timeout *fsm_overall_timeouts; - ddsrt_mutex_t fsm_fsms_mutex; - dds_security_fsm *fsm_fsms; - fsm_state_timeout *fsm_next_state_timeout; - ddsrt_mutex_t fsm_state_timeout_mutex; - ddsrt_cond_t fsm_event_cond; - ddsrt_mutex_t fsm_event_cond_mutex; +struct dds_security_fsm_control +{ + ddsrt_mutex_t lock; + ddsrt_cond_t cond; + struct thread_state1 *ts; + struct q_globals *gv; + struct dds_security_fsm *first_fsm; + struct dds_security_fsm *last_fsm; + struct fsm_event *event_queue; + ddsrt_fibheap_t timers; + bool running; +}; - // Overall timeout guard - ddsrt_cond_t fsm_overall_timeout_cond; - ddsrt_mutex_t fsm_overall_timeout_cond_mutex; -} dds_security_fsm_context; +static int compare_timer_event (const void *va, const void *vb); +static void fsm_delete (struct dds_security_fsm_control *control, struct dds_security_fsm *fsm); -static dds_security_fsm_context *fsm_context = NULL; +const ddsrt_fibheap_def_t timer_events_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct fsm_timer_event, heapnode), compare_timer_event); -// Thread safe initialization of the Generic State Machine Utility -bool dds_security_fsm_initialized = false; -static ddsrt_atomic_uint32_t _fsmInitCount = DDSRT_ATOMIC_UINT32_INIT(0); +static int compare_timer_event (const void *va, const void *vb) +{ + const struct fsm_timer_event *a = va; + const struct fsm_timer_event *b = vb; + return (a->endtime == b->endtime) ? 0 : (a->endtime < b->endtime) ? -1 : 1; +} -static void fsm_dispatch(struct dds_security_fsm *fsm, int event_id, int lifo) { - fsm_event *event; - dds_security_fsm_context *context; - - assert(fsm); - - if (fsm->size < 0) { - /* This fsm is cleaned up (but probably not freed yet). - * So, ignore the new event. */ - return; - } - - context = fsm->context; - assert(context); +static void fsm_dispatch (struct dds_security_fsm *fsm, int event_id, bool lifo) +{ + struct dds_security_fsm_control *control = fsm->control; + struct fsm_event *event; if (fsm->debug_func) { fsm->debug_func(fsm, @@ -101,7 +97,7 @@ static void fsm_dispatch(struct dds_security_fsm *fsm, int event_id, int lifo) { fsm->current, event_id, fsm->arg); } - event = ddsrt_malloc(sizeof(fsm_event)); + event = ddsrt_malloc (sizeof(struct fsm_event)); event->fsm = fsm; event->event_id = event_id; event->next = NULL; @@ -109,641 +105,422 @@ static void fsm_dispatch(struct dds_security_fsm *fsm, int event_id, int lifo) { if (lifo) { /* Insert event at the top of the event list */ - if (context->fsm_queue) { - context->fsm_queue->prev = event; + if (control->event_queue) { + control->event_queue->prev = event; } - event->next = context->fsm_queue; - context->fsm_queue = event; + event->next = control->event_queue; + control->event_queue = event; } else { /* Insert FIFO event */ - if (context->fsm_queue) { - fsm_event *last = context->fsm_queue; + if (control->event_queue) { + struct fsm_event *last = control->event_queue; while (last->next != NULL ) { last = last->next; } last->next = event; event->prev = last; } else { - context->fsm_queue = event; + control->event_queue = event; } } } -static void fsm_set_next_state_timeout(dds_security_fsm_context *context, - dds_security_fsm *ignore) { - dds_security_fsm *fsm; +static void set_state_timer (struct dds_security_fsm *fsm) +{ + struct dds_security_fsm_control *control = fsm->control; - ddsrt_mutex_lock(&context->fsm_event_cond_mutex); - - // reset the current time - context->fsm_next_state_timeout->endtime = DDS_NEVER; - context->fsm_next_state_timeout->fsm = NULL; - - fsm = context->fsm_fsms; - while (fsm) { - if ((fsm->current) && (fsm->current->timeout) && (fsm != ignore)) { - // first set the endtime of this state (if not set) - if (fsm->current_state_endtime == 0) { - fsm->current_state_endtime = ddsrt_time_add_duration(dds_time(), - fsm->current->timeout); - } - // Initialize the current endtime - if (context->fsm_next_state_timeout->fsm == NULL) { - context->fsm_next_state_timeout->endtime = fsm->current_state_endtime; - context->fsm_next_state_timeout->fsm = fsm; - } else if (fsm->current_state_endtime - < context->fsm_next_state_timeout->endtime) { - context->fsm_next_state_timeout->endtime = fsm->current_state_endtime; - context->fsm_next_state_timeout->fsm = fsm; - } - } - fsm = fsm->next; + if (fsm->current && fsm->current->timeout > 0 && fsm->current->timeout != DDS_NEVER) + { + fsm->state_timeout_event.endtime = ddsrt_time_add_duration (dds_time(), fsm->current->timeout); + ddsrt_fibheap_insert (&timer_events_fhdef, &control->timers, &fsm->state_timeout_event); } - - ddsrt_mutex_unlock(&context->fsm_event_cond_mutex); + else + fsm->state_timeout_event.endtime = DDS_NEVER; } -static void fsm_state_change(fsm_event *event) { - dds_security_fsm *fsm = event->fsm; - dds_security_fsm_context *context = fsm->context; +static void clear_state_timer (struct dds_security_fsm *fsm) +{ + struct dds_security_fsm_control *control = fsm->control; + + if (fsm->current && fsm->state_timeout_event.endtime != DDS_NEVER) + ddsrt_fibheap_delete (&timer_events_fhdef, &control->timers, &fsm->state_timeout_event); +} + +static void clear_overall_timer (struct dds_security_fsm *fsm) +{ + struct dds_security_fsm_control *control = fsm->control; + + if (fsm->current && fsm->overall_timeout_event.endtime != DDS_NEVER) + ddsrt_fibheap_delete (&timer_events_fhdef, &control->timers, &fsm->overall_timeout_event); +} + +static dds_time_t first_timeout (struct dds_security_fsm_control *control) +{ + struct fsm_timer_event *min; + if ((min = ddsrt_fibheap_min (&timer_events_fhdef, &control->timers)) != NULL) + return min->endtime; + return DDS_NEVER; +} + +static void fsm_check_auto_state_change (struct dds_security_fsm *fsm) +{ + if (fsm->current) + { + uint32_t i; + + for (i = 0; i < fsm->size; i++) + { + if (fsm->transitions[i].begin == fsm->current && fsm->transitions[i].event_id == DDS_SECURITY_FSM_EVENT_AUTO) + { + fsm_dispatch (fsm, DDS_SECURITY_FSM_EVENT_AUTO, true); + break; + } + } + } +} + +static void fsm_state_change (struct dds_security_fsm_control *control, struct fsm_event *event) +{ + struct dds_security_fsm *fsm = event->fsm; int event_id = event->event_id; - int i, j; + uint32_t i; - if (fsm->debug_func) { - fsm->debug_func(fsm, DDS_SECURITY_FSM_DEBUG_ACT_HANDLING, fsm->current, event_id, - fsm->arg); - } + if (fsm->active) + { + if (fsm->debug_func) + fsm->debug_func (fsm, DDS_SECURITY_FSM_DEBUG_ACT_HANDLING, fsm->current, event_id, fsm->arg); - for (i = 0; !context->fsm_teardown && i < fsm->size; i++) { - if ((fsm->transitions[i].begin == fsm->current) - && (fsm->transitions[i].event_id == event_id)) { - /* Transition. */ - if (fsm->transitions[i].func) { - fsm->transitions[i].func(fsm, fsm->arg); - } - /* New state. */ - fsm->current = fsm->transitions[i].end; - if (fsm->current) { - if (fsm->current->func) { - fsm->current->func(fsm, fsm->arg); - } - /* Reset timeout. */ - fsm->current_state_endtime = ddsrt_time_add_duration(dds_time(), - fsm->current->timeout); - /* Check if an auto transition is to be dispatched */ - for (j = 0; j < fsm->size; j++) { - if ((fsm->transitions[j].begin == fsm->current) - && (fsm->transitions[j].event_id == DDS_SECURITY_FSM_EVENT_AUTO)) { - dds_security_fsm_dispatch_direct(fsm, DDS_SECURITY_FSM_EVENT_AUTO); - } - } + for (i = 0; i < fsm->size; i++) + { + if ((fsm->transitions[i].begin == fsm->current) && (fsm->transitions[i].event_id == event_id)) + { + clear_state_timer (fsm); + fsm->current = fsm->transitions[i].end; + set_state_timer (fsm); + + ddsrt_mutex_unlock (&control->lock); + if (fsm->transitions[i].func) + fsm->transitions[i].func (fsm, fsm->arg); + if (fsm->current && fsm->current->func) + fsm->current->func (fsm, fsm->arg); + ddsrt_mutex_lock (&control->lock); + fsm_check_auto_state_change (fsm); + break; } } } + else if (event_id == DDS_SECURITY_FSM_EVENT_DELETE) + fsm_delete (control, fsm); + } -static uint32_t -fsm_thread(void *a) { - dds_security_fsm_context *context = a; - dds_duration_t dur_to_wait; - dds_time_t now = DDS_TIME_INVALID; - fsm_event *event; +static void fsm_handle_timeout (struct dds_security_fsm_control *control, struct fsm_timer_event *timer_event) +{ + struct dds_security_fsm *fsm = timer_event->fsm; - while (!context->fsm_teardown) { - event = NULL; - - ddsrt_mutex_lock(&context->fsm_event_cond_mutex); - if (!context->fsm_queue) { - if (context->fsm_next_state_timeout->endtime == DDS_NEVER) { - dur_to_wait = DDS_NEVER; - } else { - now = dds_time(); - dur_to_wait = context->fsm_next_state_timeout->endtime - now; - } - if (dur_to_wait > 0) { - if (ddsrt_cond_waitfor(&context->fsm_event_cond, - &context->fsm_event_cond_mutex, dur_to_wait) == false) { - if (context->fsm_next_state_timeout->fsm) { - /* Next timeout could have changed. */ - if (context->fsm_next_state_timeout->endtime != DDS_NEVER - && (context->fsm_next_state_timeout->endtime - now <= 0)) { - fsm_dispatch(context->fsm_next_state_timeout->fsm, - DDS_SECURITY_FSM_EVENT_TIMEOUT, 1); - } - } - } - } else { - if (context->fsm_next_state_timeout->fsm) { - fsm_dispatch(context->fsm_next_state_timeout->fsm, - DDS_SECURITY_FSM_EVENT_TIMEOUT, 1); - } - } - } else { - event = context->fsm_queue; - context->fsm_queue = context->fsm_queue->next; - if (context->fsm_queue) { - context->fsm_queue->prev = NULL; - } - ddsrt_atomic_inc32(&(event->fsm->ref_cnt)); + if (fsm->active) + { + switch (timer_event->kind) + { + case FSM_TIMEOUT_STATE: + fsm_dispatch (fsm, DDS_SECURITY_FSM_EVENT_TIMEOUT, true); + break; + case FSM_TIMEOUT_OVERALL: + ddsrt_mutex_unlock (&control->lock); + if (fsm->overall_timeout_action) + fsm->overall_timeout_action (fsm, fsm->arg); + ddsrt_mutex_lock (&control->lock); + break; } - ddsrt_mutex_unlock(&context->fsm_event_cond_mutex); - - if (event) { - fsm_state_change(event); - if (ddsrt_atomic_dec32_nv(&(event->fsm->ref_cnt)) == 0) { - ddsrt_free(event->fsm); - } - ddsrt_free(event); - } - fsm_set_next_state_timeout(context, NULL); } + + /* mark timer event as being processed */ + timer_event->endtime = DDS_NEVER; +} + +static uint32_t handle_events (struct dds_security_fsm_control *control) +{ + struct thread_state1 * const ts1 = lookup_thread_state (); + + ddsrt_mutex_lock (&control->lock); + thread_state_awake (ts1, control->gv); + while (control->running) + { + if (control->event_queue) + { + struct fsm_event *event = control->event_queue; + + control->event_queue = event->next; + if (control->event_queue) + control->event_queue->prev = NULL; + fsm_state_change (control, event); + ddsrt_free (event); + } + else + { + dds_time_t timeout = first_timeout (control); + + if (timeout > dds_time ()) + { + thread_state_asleep (ts1); + (void)ddsrt_cond_waituntil( &control->cond, &control->lock, timeout); + thread_state_awake (ts1, control->gv); + } + else + { + struct fsm_timer_event *timer_event = ddsrt_fibheap_extract_min (&timer_events_fhdef, &control->timers); + fsm_handle_timeout (control, timer_event); + } + } + } + thread_state_asleep (ts1); + ddsrt_mutex_unlock (&control->lock); + return 0; } -static fsm_overall_timeout * -fsm_get_first_overall_timeout(dds_security_fsm_context *context) { - fsm_overall_timeout *timeout; - fsm_overall_timeout *first_timeout; - dds_time_t first_time = DDS_NEVER; +void dds_security_fsm_set_timeout (struct dds_security_fsm *fsm, dds_security_fsm_action action, dds_duration_t timeout) +{ + assert(fsm); + assert(fsm->control); + assert(timeout > 0); - timeout = context->fsm_overall_timeouts; - first_timeout = context->fsm_overall_timeouts; - while (timeout) { - if (timeout->endtime < first_time) { - first_time = timeout->endtime; - first_timeout = timeout; + ddsrt_mutex_lock (&fsm->control->lock); + if (fsm->active) + { + if (timeout != DDS_NEVER) + { + clear_overall_timer(fsm); + fsm->overall_timeout_action = action; + fsm->overall_timeout_event.endtime = ddsrt_time_add_duration(dds_time(), timeout); + ddsrt_fibheap_insert (&timer_events_fhdef, &fsm->control->timers, &fsm->overall_timeout_event); + if (fsm->overall_timeout_event.endtime < first_timeout(fsm->control)) + ddsrt_cond_signal (&fsm->control->cond); } - timeout = timeout->next; + else + clear_overall_timer (fsm); } - - return first_timeout; + ddsrt_mutex_unlock (&fsm->control->lock); } -static void fsm_remove_overall_timeout_from_list(dds_security_fsm_context *context, - fsm_overall_timeout *timeout) { - fsm_overall_timeout *tmp_next_timeout; - fsm_overall_timeout *tmp_prev_timeout; +void dds_security_fsm_dispatch (struct dds_security_fsm *fsm, int32_t event_id, bool prio) +{ + assert(fsm); + assert(fsm->control); - if (timeout) { - - tmp_next_timeout = timeout->next; - tmp_prev_timeout = timeout->prev; - if (tmp_prev_timeout) { - tmp_prev_timeout->next = tmp_next_timeout; - } - if (tmp_next_timeout) { - tmp_next_timeout->prev = tmp_prev_timeout; - } - - if (timeout == context->fsm_overall_timeouts) { - context->fsm_overall_timeouts = tmp_next_timeout; - } - - ddsrt_free(timeout); - timeout = NULL; + ddsrt_mutex_lock (&fsm->control->lock); + if (fsm->active) + { + fsm_dispatch (fsm, event_id, prio); + ddsrt_cond_signal (&fsm->control->cond); } + ddsrt_mutex_unlock (&fsm->control->lock); } -static uint32_t -fsm_run_timeout(void *arg) { - dds_security_fsm_context *context = arg; - dds_return_t result; - fsm_overall_timeout *to; - dds_time_t time_to_wait; - dds_time_t now; +const dds_security_fsm_state * dds_security_fsm_current_state (struct dds_security_fsm *fsm) +{ + const dds_security_fsm_state *state; - while (!context->fsm_teardown) { - ddsrt_mutex_lock(&context->fsm_overall_timeout_cond_mutex); - to = fsm_get_first_overall_timeout(context); - if (to) { - struct dds_security_fsm *fsm = to->fsm; - ddsrt_atomic_inc32(&(fsm->ref_cnt)); + assert(fsm); + assert(fsm->active); - result = DDS_RETCODE_TIMEOUT; - now = dds_time(); - if (to->endtime > now) { - time_to_wait = to->endtime - now; - result = ddsrt_cond_waitfor(&context->fsm_overall_timeout_cond, - &context->fsm_overall_timeout_cond_mutex, time_to_wait); - } + ddsrt_mutex_lock (&fsm->control->lock); + state = fsm->current; + ddsrt_mutex_unlock (&fsm->control->lock); - if (result == DDS_RETCODE_TIMEOUT) { - /* Prevent calling timeout when the fsm has been cleaned. */ - dds_security_fsm_action func = to->func; - fsm_remove_overall_timeout_from_list(context, to); - if (fsm->size > 0) { - ddsrt_mutex_unlock(&context->fsm_overall_timeout_cond_mutex); - func(fsm, fsm->arg); - ddsrt_mutex_lock(&context->fsm_overall_timeout_cond_mutex); - } - } - - if (ddsrt_atomic_dec32_nv(&(fsm->ref_cnt)) == 0) { - ddsrt_free(fsm); - } - } else { - ddsrt_cond_wait(&context->fsm_overall_timeout_cond, - &context->fsm_overall_timeout_cond_mutex); - } - ddsrt_mutex_unlock(&context->fsm_overall_timeout_cond_mutex); - } - return 0; + return state; } -static void fsm_remove_fsm_list(dds_security_fsm *fsm) { - dds_security_fsm_context *context; - dds_security_fsm *tmp_next_fsm; - dds_security_fsm *tmp_prev_fsm; +void dds_security_fsm_set_debug (struct dds_security_fsm *fsm, dds_security_fsm_debug func) +{ + assert(fsm); - if (fsm) { - context = fsm->context; - - ddsrt_mutex_lock(&context->fsm_fsms_mutex); - tmp_next_fsm = fsm->next; - tmp_prev_fsm = fsm->prev; - if (tmp_prev_fsm) { - tmp_prev_fsm->next = tmp_next_fsm; - } - if (tmp_next_fsm) { - tmp_next_fsm->prev = tmp_prev_fsm; - } - if (fsm == context->fsm_fsms) { - context->fsm_fsms = tmp_next_fsm; - } - ddsrt_mutex_unlock(&context->fsm_fsms_mutex); - - ddsrt_mutex_lock(&context->fsm_overall_timeout_cond_mutex); - ddsrt_cond_signal(&context->fsm_overall_timeout_cond); - ddsrt_mutex_unlock(&context->fsm_overall_timeout_cond_mutex); - } + ddsrt_mutex_lock (&fsm->control->lock); + fsm->debug_func = func; + ddsrt_mutex_unlock (&fsm->control->lock); } -static ddsrt_thread_t fsm_thread_create( const char *name, - ddsrt_thread_routine_t f, void *arg) { - ddsrt_thread_t tid; - ddsrt_threadattr_t threadAttr; +static bool fsm_validate (const dds_security_fsm_transition *transitions, uint32_t size) +{ + uint32_t i; - ddsrt_threadattr_init(&threadAttr); - if (ddsrt_thread_create(&tid, name, &threadAttr, f, arg) != DDS_RETCODE_OK) { - memset(&tid, 0, sizeof(ddsrt_thread_t)); - } - return tid; -} -#ifdef AT_PROC_EXIT_IMPLEMENTED -static void fsm_thread_destroy( ddsrt_thread_t tid) { - uint32_t thread_result; - - (void) ddsrt_thread_join( tid, &thread_result); -} -#endif - -struct dds_security_fsm_context * -dds_security_fsm_context_create( dds_security_fsm_thread_create_func thr_create_func) { - struct dds_security_fsm_context *context; - - context = ddsrt_malloc(sizeof(*context)); - - context->fsm_next_state_timeout = ddsrt_malloc(sizeof(fsm_state_timeout)); - context->fsm_next_state_timeout->endtime = DDS_NEVER; - context->fsm_next_state_timeout->fsm = NULL; - - context->fsm_teardown = false; - context->fsm_queue = NULL; - context->fsm_overall_timeouts = NULL; - context->fsm_fsms = NULL; - - (void) ddsrt_mutex_init( &context->fsm_fsms_mutex ); - - // Overall timeout guard - (void) ddsrt_mutex_init( &context->fsm_overall_timeout_cond_mutex ); - (void) ddsrt_cond_init( &context->fsm_overall_timeout_cond ); - - // State timeouts - (void) ddsrt_mutex_init(&context->fsm_state_timeout_mutex ); - - // Events - (void) ddsrt_mutex_init(&context->fsm_event_cond_mutex ); - (void) ddsrt_cond_init(&context->fsm_event_cond ); - - context->fsm_tid = thr_create_func( "dds_security_fsm", fsm_thread, context); - context->fsm_timeout_tid = thr_create_func( "dds_security_fsm_timeout", - fsm_run_timeout, context); - - return context; -} - -void dds_security_fsm_context_destroy(dds_security_fsm_context *context, - dds_security_fsm_thread_destroy_func thr_destroy_func) { - if (context) { - context->fsm_teardown = true; - - ddsrt_mutex_lock( &context->fsm_overall_timeout_cond_mutex); - ddsrt_cond_signal( &context->fsm_overall_timeout_cond); - ddsrt_mutex_unlock( &context->fsm_overall_timeout_cond_mutex); - - ddsrt_mutex_lock(&context->fsm_event_cond_mutex); - ddsrt_cond_signal(&context->fsm_event_cond); - ddsrt_mutex_unlock(&context->fsm_event_cond_mutex); - - thr_destroy_func( context->fsm_tid); - ddsrt_mutex_destroy(&context->fsm_event_cond_mutex); - ddsrt_cond_destroy(&context->fsm_event_cond); - - thr_destroy_func( context->fsm_timeout_tid); - ddsrt_mutex_destroy(&context->fsm_fsms_mutex); - ddsrt_mutex_destroy(&context->fsm_overall_timeout_cond_mutex); - ddsrt_cond_destroy(&context->fsm_overall_timeout_cond); - - ddsrt_free(context->fsm_next_state_timeout); - } -} -#ifdef AT_PROC_EXIT_IMPLEMENTED -static void fsm_fini(void) { - dds_security_fsm_context_destroy(fsm_context, NULL, fsm_thread_destroy); - - /* os_osExit(); ???? */ -} - -#endif -static bool fsm_init_once(void) { - bool ret = true; - uint32_t initCount; - - initCount = ddsrt_atomic_inc32_nv(&_fsmInitCount); - - if (initCount == 1) { - assert( dds_security_fsm_initialized == false ); - - /* ddsrt_osInit(); ??? */ - - fsm_context = dds_security_fsm_context_create( fsm_thread_create); - - if (fsm_context) { - /* os_procAtExit( fsm_fini ); ??? */ - dds_security_fsm_initialized = true; - } else { - ret = false; - } - } else { - if (dds_security_fsm_initialized == false) { - /* Another thread is currently initializing the fsm. Since - * both results (osr_fsm and osr_timeout) should be ddsrt_resultSuccess - * a sleep is performed, to ensure that (if succeeded) successive - * init calls will also actually pass. - */ - dds_sleepfor( DDS_MSECS( 100 )); - } - if (dds_security_fsm_initialized == false) { - /* Initialization did not succeed, undo increment and return error */ - initCount = ddsrt_atomic_dec32_nv(&_fsmInitCount); - ret = false; - } - } - return ret; -} - -static int /* 1 = ok, other = error */ -fsm_validate(const dds_security_fsm_transition *transitions, int size) { - int i; - - for (i = 0; i < size; i++) { + for (i = 0; i < size; i++) + { /* It needs to have a start. */ - if ((transitions[i].begin == NULL ) - && (transitions[i].event_id == DDS_SECURITY_FSM_EVENT_AUTO)) { - return 1; - } + if (transitions[i].begin && transitions[i].event_id == DDS_SECURITY_FSM_EVENT_AUTO) + return true; } - - return 0; + return true; } -struct dds_security_fsm * -dds_security_fsm_create(struct dds_security_fsm_context *context, - const dds_security_fsm_transition *transitions, int size, void *arg) { - struct dds_security_fsm* fsm = NULL; - struct dds_security_fsm_context *ctx = NULL; - - assert(transitions); - assert(size > 0); - - if (context == NULL) { - if (fsm_init_once()) { - ctx = fsm_context; - } - } else { - ctx = context; +static void add_fsm_to_list (struct dds_security_fsm_control *control, struct dds_security_fsm *fsm) +{ + fsm->next_fsm = NULL; + fsm->prev_fsm = control->last_fsm; + if (control->last_fsm) + { + assert(control->first_fsm != NULL); + control->last_fsm->next_fsm = fsm; } + else + { + assert(control->first_fsm == NULL); + control->first_fsm = fsm; + } + control->last_fsm = fsm; +} - if (ctx) { - if (fsm_validate(transitions, size) == 1) { - fsm = ddsrt_malloc(sizeof(struct dds_security_fsm)); - fsm->transitions = transitions; - fsm->size = size; - fsm->arg = arg; - fsm->current = NULL; - fsm->debug_func = NULL; - fsm->next = NULL; - fsm->prev = NULL; - fsm->context = ctx; - ddsrt_atomic_st32( &fsm->ref_cnt, 1 ); - fsm->current_state_endtime = 0; +static void remove_fsm_from_list (struct dds_security_fsm_control *control, struct dds_security_fsm *fsm) +{ + if (fsm->prev_fsm) + fsm->prev_fsm->next_fsm = fsm->next_fsm; + else + control->first_fsm = fsm->next_fsm; - ddsrt_mutex_lock(&fsm->context->fsm_fsms_mutex); - if (fsm->context->fsm_fsms) { - dds_security_fsm *last = fsm->context->fsm_fsms; - while (last->next != NULL ) { - last = last->next; - } - last->next = fsm; - fsm->prev = last; - } else { - fsm->context->fsm_fsms = fsm; - } - ddsrt_mutex_unlock(&fsm->context->fsm_fsms_mutex); - } + if (fsm->next_fsm) + fsm->next_fsm->prev_fsm = fsm->prev_fsm; + else + control->last_fsm = fsm->prev_fsm; +} + +struct dds_security_fsm * dds_security_fsm_create (struct dds_security_fsm_control *control, const dds_security_fsm_transition *transitions, uint32_t size, void *arg) +{ + struct dds_security_fsm *fsm = NULL; + + assert(control); + assert(transitions); + + if (fsm_validate (transitions, size)) + { + fsm = ddsrt_malloc (sizeof(struct dds_security_fsm)); + fsm->transitions = transitions; + fsm->size = size; + fsm->arg = arg; + fsm->current = NULL; + fsm->debug_func = NULL; + fsm->overall_timeout_action = NULL; + fsm->state_timeout_event.kind = FSM_TIMEOUT_STATE; + fsm->state_timeout_event.endtime = DDS_NEVER; + fsm->state_timeout_event.fsm = fsm; + fsm->overall_timeout_event.kind = FSM_TIMEOUT_OVERALL; + fsm->overall_timeout_event.endtime = DDS_NEVER; + fsm->overall_timeout_event.fsm = fsm; + fsm->active = true; + fsm->next_fsm = NULL; + fsm->prev_fsm = NULL; + fsm->control = control; + + ddsrt_mutex_lock (&control->lock); + add_fsm_to_list (control, fsm); + ddsrt_mutex_unlock (&control->lock); } return fsm; } -void dds_security_fsm_start(struct dds_security_fsm *fsm) { - assert(fsm); - dds_security_fsm_dispatch(fsm, DDS_SECURITY_FSM_EVENT_AUTO); +void +dds_security_fsm_start (struct dds_security_fsm *fsm) +{ + dds_security_fsm_dispatch(fsm, DDS_SECURITY_FSM_EVENT_AUTO, false); } -void dds_security_fsm_set_timeout(struct dds_security_fsm *fsm, dds_security_fsm_action func, - dds_time_t timeout) { - fsm_overall_timeout *to; - dds_security_fsm_context *context; - - assert(fsm); - - context = fsm->context; - assert(context); - - to = ddsrt_malloc(sizeof(fsm_overall_timeout)); - to->fsm = fsm; - to->func = func; - to->endtime = ddsrt_time_add_duration( dds_time(), timeout); - to->next = NULL; - to->prev = NULL; - - ddsrt_mutex_lock(&context->fsm_overall_timeout_cond_mutex); - if (context->fsm_overall_timeouts) { - fsm_overall_timeout *last = context->fsm_overall_timeouts; - while (last->next != NULL ) { - last = last->next; - } - last->next = to; - to->prev = last; - } else { - context->fsm_overall_timeouts = to; - } - ddsrt_cond_signal(&context->fsm_overall_timeout_cond); - ddsrt_mutex_unlock(&context->fsm_overall_timeout_cond_mutex); -} - -void dds_security_fsm_set_debug(struct dds_security_fsm *fsm, dds_security_fsm_debug func) { - dds_security_fsm_context *context; - - assert(fsm); - - context = fsm->context; - assert(context); - - ddsrt_mutex_lock(&context->fsm_overall_timeout_cond_mutex); - fsm->debug_func = func; - ddsrt_mutex_unlock(&context->fsm_overall_timeout_cond_mutex); -} - -void dds_security_fsm_dispatch(struct dds_security_fsm *fsm, int32_t event_id) { - dds_security_fsm_context *context; - - assert(fsm); - - context = fsm->context; - assert(context); - - ddsrt_mutex_lock(&context->fsm_event_cond_mutex); - fsm_dispatch(fsm, event_id, 0); - ddsrt_cond_signal(&context->fsm_event_cond); - ddsrt_mutex_unlock(&context->fsm_event_cond_mutex); -} - -void dds_security_fsm_dispatch_direct(struct dds_security_fsm *fsm, int32_t event_id) { - dds_security_fsm_context *context; - - assert(fsm); - - context = fsm->context; - assert(context); - - ddsrt_mutex_lock(&context->fsm_event_cond_mutex); - fsm_dispatch(fsm, event_id, 1); - ddsrt_cond_signal(&context->fsm_event_cond); - ddsrt_mutex_unlock(&context->fsm_event_cond_mutex); -} - -const dds_security_fsm_state* -dds_security_fsm_current_state(struct dds_security_fsm *fsm) { - assert(fsm); - return fsm->current; -} - -void dds_security_fsm_cleanup(struct dds_security_fsm *fsm) { - dds_security_fsm_context *context; - fsm_event *event; - fsm_event *tmp_prev_event; - fsm_event *tmp_next_event; - fsm_overall_timeout *timeout; - - assert(fsm); - - context = fsm->context; - assert(context); - - // Signal the timeout thread. - // First hold to lock to the overall timeout list - // so that the next timeout can't be determined until - // we've done removing the overall timeout of this fsm - - // Signal the thread so that it's not using timeout structs - ddsrt_mutex_lock(&context->fsm_overall_timeout_cond_mutex); - ddsrt_cond_signal(&context->fsm_overall_timeout_cond); - - timeout = context->fsm_overall_timeouts; - - // Search the overall timeout of this fsm - while (timeout) { - if (timeout->fsm == fsm) { - break; - } - timeout = timeout->next; - } - fsm_remove_overall_timeout_from_list(context, timeout); - ddsrt_mutex_unlock(&context->fsm_overall_timeout_cond_mutex); - - /* The current fsm could be the one that would trigger a possible timeout. - * Reset the state timeout and make sure it's not the current fsm. */ - fsm_set_next_state_timeout(context, fsm); - - /* Now, remove all possible events from the queue related to the fsm. */ - ddsrt_mutex_lock(&context->fsm_event_cond_mutex); - event = context->fsm_queue; - while (event) { - if (event->fsm == fsm) { - tmp_next_event = event->next; - tmp_prev_event = event->prev; - if (tmp_prev_event) { - tmp_prev_event->next = tmp_next_event; - } - if (tmp_next_event) { - tmp_next_event->prev = tmp_prev_event; - } - if (event == context->fsm_queue) { - context->fsm_queue = tmp_next_event; - } - ddsrt_free(event); - event = tmp_next_event; - } else { - event = event->next; - } - } - ddsrt_cond_signal(&context->fsm_event_cond); - ddsrt_mutex_unlock(&context->fsm_event_cond_mutex); -} - -void dds_security_fsm_free(struct dds_security_fsm *fsm) { - ddsrt_tid_t self = ddsrt_gettid_for_thread( ddsrt_thread_self() ); - dds_security_fsm_context *context; - - assert(fsm); - - context = fsm->context; - assert(context); - - /* Indicate termination. */ - fsm->size = -1; - - /* Cleanup stuff. */ - dds_security_fsm_cleanup(fsm); - fsm_remove_fsm_list(fsm); - - /* Is this being freed from the FSM context? */ - if ((self == ddsrt_gettid_for_thread( context->fsm_tid ) ) - || (self == ddsrt_gettid_for_thread( context->fsm_timeout_tid ) ) ) { - /* Yes. - * Just reduce the reference count and let the garbage collection be - * done by the FSM context after event handling. */ - ddsrt_atomic_dec32(&(fsm->ref_cnt)); - } else { - /* No. - * Block the outside thread until a possible concurrent event - * has being handled. */ - while (ddsrt_atomic_ld32( &(fsm->ref_cnt)) > 1) { - /* Currently, an event is still being handled for this FSM. */ - dds_sleepfor( 10 * DDS_NSECS_IN_MSEC ); - } - /* We have the only reference, so it's safe to free the FSM. */ - ddsrt_free(fsm); +static void fsm_deactivate (struct dds_security_fsm *fsm, bool gen_del_event) +{ + if (fsm->active) + { + fsm->active = false; + clear_state_timer (fsm); + clear_overall_timer (fsm); + fsm->current = NULL; + if (gen_del_event) + fsm_dispatch (fsm, DDS_SECURITY_FSM_EVENT_DELETE, false); } } + +void dds_security_fsm_free (struct dds_security_fsm *fsm) +{ + struct dds_security_fsm_control *control; + + assert(fsm); + assert(fsm->control); + + control = fsm->control; + ddsrt_mutex_lock (&control->lock); + fsm_deactivate (fsm, true); + ddsrt_mutex_unlock (&control->lock); +} + +static void fsm_delete (struct dds_security_fsm_control *control, struct dds_security_fsm *fsm) +{ + fsm_deactivate (fsm, false); + remove_fsm_from_list (control, fsm); + ddsrt_free(fsm); +} + +struct dds_security_fsm_control * dds_security_fsm_control_create (struct q_globals *gv) +{ + struct dds_security_fsm_control *control; + + control = ddsrt_malloc (sizeof(*control)); + control->running = false; + control->event_queue = NULL; + control->first_fsm = NULL; + control->last_fsm = NULL; + control->gv = gv; + ddsrt_mutex_init (&control->lock); + ddsrt_cond_init (&control->cond); + ddsrt_fibheap_init (&timer_events_fhdef, &control->timers); + + return control; +} + +void dds_security_fsm_control_free (struct dds_security_fsm_control *control) +{ + struct dds_security_fsm *fsm; + struct fsm_event *event; + + assert(control); + assert(!control->running); + + while ((fsm = control->first_fsm) != NULL) + { + control->first_fsm = fsm->next_fsm; + fsm_deactivate (fsm, false); + ddsrt_free (fsm); + } + while ((event = control->event_queue) != NULL) + { + control->event_queue = event->next; + ddsrt_free (event); + } + + ddsrt_cond_destroy (&control->cond); + ddsrt_mutex_destroy (&control->lock); + ddsrt_free (control); +} + +dds_return_t dds_security_fsm_control_start (struct dds_security_fsm_control *control, const char *name) +{ + dds_return_t rc; + const char *fsm_name = name ? name : "fsm"; + + assert(control); + + control->running = true; + rc = create_thread (&control->ts, control->gv, fsm_name, (uint32_t (*) (void *)) handle_events, control); + + return rc; +} + +void dds_security_fsm_control_stop (struct dds_security_fsm_control *control) +{ + assert(control); + assert(control->running); + + ddsrt_mutex_lock (&control->lock); + control->running = false; + ddsrt_cond_signal (&control->cond); + ddsrt_mutex_unlock (&control->lock); + + join_thread (control->ts); + control->ts = NULL; +} diff --git a/src/security/core/tests/CMakeLists.txt b/src/security/core/tests/CMakeLists.txt index e002ba4..40a6650 100644 --- a/src/security/core/tests/CMakeLists.txt +++ b/src/security/core/tests/CMakeLists.txt @@ -27,13 +27,10 @@ target_include_directories( "$>" "$" "$" - "$" + "$" + "$" ) target_link_libraries(cunit_security_core PRIVATE ddsc security_api) target_include_directories(cunit_security_core PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") - - - -# configure_file("config_env.h.in" "config_env.h") \ No newline at end of file diff --git a/src/security/core/tests/tc_fsm.c b/src/security/core/tests/tc_fsm.c index 442b921..c2c7647 100644 --- a/src/security/core/tests/tc_fsm.c +++ b/src/security/core/tests/tc_fsm.c @@ -1,43 +1,45 @@ -#include "dds/security/core/dds_security_fsm.h" -#include "dds/ddsrt/sync.h" -#include "dds/ddsrt/misc.h" +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ #include #include + +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/misc.h" + #include "CUnit/CUnit.h" #include "CUnit/Test.h" +#include "dds/dds.h" +#include "dds__types.h" +#include "dds__entity.h" +#include "dds/security/core/dds_security_fsm.h" #define CHECK_BIT(var, pos) ((var) & (1<<(pos))) #define FSM_AUTH_ARG 10 -#define DB_TC_PRINT_DEBUG (false) +#define DB_TC_PRINT_DEBUG (true) -static struct dds_security_fsm *fsm_auth; -static struct dds_security_fsm *fsm_test; -static struct dds_security_fsm *fsm_timeout; -static struct dds_security_fsm *fsm_timeout2; -static struct dds_security_fsm *fsm_timeout3; +static dds_entity_t g_participant = 0; +static struct dds_security_fsm_control *g_fsm_control = NULL; +static const dds_duration_t msec100 = DDS_MSECS(100); -static uint32_t visited_auth = 0; -static uint32_t visited_test = 0; -static uint32_t visited_timeout = 0; +//static int fsm_arg = FSM_AUTH_ARG; -uint32_t correct_fsm = 0; -uint32_t correct_arg = 0; -uint32_t correct_fsm_timeout = 0; -uint32_t correct_arg_timeout = 0; -static ddsrt_cond_t stop_timeout_cond; -static ddsrt_mutex_t stop_timeout_cond_mutex; -static uint32_t stop_timeout_cond_cnt = 0; -static int validate_remote_identity_first = 1; -static int begin_handshake_reply_first = 1; -static int do_stuff_counter = 0; -static int do_other_stuff_counter = 0; -/* +/********************************************************************** * Authentication State Machine properties and methods - */ + **********************************************************************/ + typedef enum { VALIDATION_PENDING_RETRY, VALIDATION_FAILED, @@ -48,8 +50,16 @@ typedef enum { PluginReturn_MAX } PluginReturn; -static PluginReturn validate_remote_identity(void) { +static struct dds_security_fsm *fsm_auth; +static uint32_t visited_auth = 0; +static uint32_t correct_fsm = 0; +static uint32_t correct_arg = 0; +static int validate_remote_identity_first = 1; +static int begin_handshake_reply_first = 1; + +static PluginReturn validate_remote_identity(void) +{ if (DB_TC_PRINT_DEBUG) { printf("validate_remote_identity - %d\n", validate_remote_identity_first); } @@ -60,8 +70,8 @@ static PluginReturn validate_remote_identity(void) { return VALIDATION_PENDING_HANDSHAKE_MESSAGE; } -static PluginReturn begin_handshake_reply(void) { - +static PluginReturn begin_handshake_reply(void) +{ if (DB_TC_PRINT_DEBUG) { printf("begin_handshake_reply - %d\n", begin_handshake_reply_first); } @@ -72,12 +82,14 @@ static PluginReturn begin_handshake_reply(void) { return VALIDATION_OK_FINAL_MESSAGE; } -static PluginReturn get_shared_secret(void) { +static PluginReturn get_shared_secret(void) +{ return VALIDATION_OK; } /* State actions. */ -static void fsm_validate_remote_identity(struct dds_security_fsm *fsm, void *arg) { +static void fsm_validate_remote_identity(struct dds_security_fsm *fsm, void *arg) +{ PluginReturn ret; DDSRT_UNUSED_ARG(arg); @@ -88,10 +100,11 @@ static void fsm_validate_remote_identity(struct dds_security_fsm *fsm, void *arg printf("[%p] State %s (ret %d)\n", fsm, __FUNCTION__, (int) ret); } - dds_security_fsm_dispatch(fsm, (int32_t) ret); + dds_security_fsm_dispatch(fsm, (int32_t) ret, false); } -static void fsm_begin_handshake_reply(struct dds_security_fsm *fsm, void *arg) { +static void fsm_begin_handshake_reply(struct dds_security_fsm *fsm, void *arg) +{ PluginReturn ret; DDSRT_UNUSED_ARG(arg); @@ -105,18 +118,18 @@ static void fsm_begin_handshake_reply(struct dds_security_fsm *fsm, void *arg) { printf("[%p] State %s (ret %d)\n", fsm, __FUNCTION__, (int) ret); } - dds_security_fsm_dispatch(fsm, (int32_t) ret); + dds_security_fsm_dispatch(fsm, (int32_t) ret, false); } /* A few states from the handshake state-machine. */ -static dds_security_fsm_state StateValidateRemoteIdentity = { - fsm_validate_remote_identity, 0}; +static dds_security_fsm_state StateValidateRemoteIdentity = {fsm_validate_remote_identity, 0}; static dds_security_fsm_state StateValRemIdentityRetryWait = {NULL, 100000000}; static dds_security_fsm_state StateHandshakeInitMessageWait = {NULL, 0}; static dds_security_fsm_state StateBeginHandshakeReply = {fsm_begin_handshake_reply, 0}; static dds_security_fsm_state StateBeginHsReplyWait = {NULL, 100000000}; -static void a(struct dds_security_fsm *fsm, void *arg) { +static void a(struct dds_security_fsm *fsm, void *arg) +{ int *fsm_arg; if (DB_TC_PRINT_DEBUG) { @@ -141,7 +154,8 @@ static void a(struct dds_security_fsm *fsm, void *arg) { visited_auth |= 1UL << 0; } -static void b(struct dds_security_fsm *fsm, void *arg) { +static void b(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) @@ -149,7 +163,8 @@ static void b(struct dds_security_fsm *fsm, void *arg) { visited_auth |= 1UL << 1; } -static void c(struct dds_security_fsm *fsm, void *arg) { +static void c(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) @@ -157,7 +172,8 @@ static void c(struct dds_security_fsm *fsm, void *arg) { visited_auth |= 1UL << 2; } -static void d(struct dds_security_fsm *fsm, void *arg) { +static void d(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) @@ -165,7 +181,8 @@ static void d(struct dds_security_fsm *fsm, void *arg) { visited_auth |= 1UL << 3; } -static void e(struct dds_security_fsm *fsm, void *arg) { +static void e(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) @@ -173,7 +190,8 @@ static void e(struct dds_security_fsm *fsm, void *arg) { visited_auth |= 1UL << 4; } -static void f(struct dds_security_fsm *fsm, void *arg) { +static void f(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) @@ -181,7 +199,8 @@ static void f(struct dds_security_fsm *fsm, void *arg) { visited_auth |= 1UL << 5; } -static void g(struct dds_security_fsm *fsm, void *arg) { +static void g(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) @@ -189,7 +208,8 @@ static void g(struct dds_security_fsm *fsm, void *arg) { visited_auth |= 1UL << 6; } -static void h(struct dds_security_fsm *fsm, void *arg) { +static void h(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) @@ -233,34 +253,35 @@ static void h(struct dds_security_fsm *fsm, void *arg) { * .-. * '-' */ -dds_security_fsm_transition HandshakeTransistions[] = - {{NULL, DDS_SECURITY_FSM_EVENT_AUTO, a, &StateValidateRemoteIdentity}, // NULL state is the start state - {&StateValidateRemoteIdentity, VALIDATION_PENDING_RETRY, b, - &StateValRemIdentityRetryWait}, - {&StateValidateRemoteIdentity, - VALIDATION_PENDING_HANDSHAKE_MESSAGE, c, - &StateHandshakeInitMessageWait}, - {&StateValRemIdentityRetryWait, - DDS_SECURITY_FSM_EVENT_TIMEOUT, d, &StateValidateRemoteIdentity}, - { - &StateHandshakeInitMessageWait, SHM_MSG_RECEIVED, e, - &StateBeginHandshakeReply}, - {&StateBeginHandshakeReply, - VALIDATION_PENDING_RETRY, f, &StateBeginHsReplyWait}, - { - &StateBeginHandshakeReply, VALIDATION_OK, g, NULL}, // Reaching NULL means end of state-diagram - {&StateBeginHsReplyWait, DDS_SECURITY_FSM_EVENT_TIMEOUT, h, - &StateBeginHandshakeReply},}; +static dds_security_fsm_transition HandshakeTransistions[] = { + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, a, &StateValidateRemoteIdentity}, // NULL state is the start state + {&StateValidateRemoteIdentity, VALIDATION_PENDING_RETRY, b, &StateValRemIdentityRetryWait}, + {&StateValidateRemoteIdentity, VALIDATION_PENDING_HANDSHAKE_MESSAGE, c, &StateHandshakeInitMessageWait}, + {&StateValRemIdentityRetryWait, DDS_SECURITY_FSM_EVENT_TIMEOUT, d, &StateValidateRemoteIdentity}, + {&StateHandshakeInitMessageWait, SHM_MSG_RECEIVED, e, &StateBeginHandshakeReply}, + {&StateBeginHandshakeReply, VALIDATION_PENDING_RETRY, f, &StateBeginHsReplyWait}, + {&StateBeginHandshakeReply, VALIDATION_OK, g, NULL}, // Reaching NULL means end of state-diagram + {&StateBeginHsReplyWait, DDS_SECURITY_FSM_EVENT_TIMEOUT, h, &StateBeginHandshakeReply} +}; +static const uint32_t HandshakeTransistionsSize = sizeof(HandshakeTransistions)/sizeof(HandshakeTransistions[0]); -/* + +/********************************************************************** * Example State Machine properties and methods - */ + **********************************************************************/ + typedef enum { eventX, eventY, eventZ, } test_events; +static struct dds_security_fsm *fsm_test; +static uint32_t visited_test = 0; +static int do_stuff_counter = 0; +static int do_other_stuff_counter = 0; + /* The functions called from the state-machine. */ -static void doStart(struct dds_security_fsm *fsm, void *arg) { +static void doStart(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) @@ -268,7 +289,8 @@ static void doStart(struct dds_security_fsm *fsm, void *arg) { visited_test |= 1UL << 0; } -static void doRestart(struct dds_security_fsm *fsm, void *arg) { +static void doRestart(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) @@ -276,7 +298,8 @@ static void doRestart(struct dds_security_fsm *fsm, void *arg) { visited_test |= 1UL << 1; } -static void doEventStuff(struct dds_security_fsm *fsm, void *arg) { +static void doEventStuff(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) @@ -284,8 +307,8 @@ static void doEventStuff(struct dds_security_fsm *fsm, void *arg) { visited_test |= 1UL << 4; } -static void doStuff(struct dds_security_fsm *fsm, void *arg) { - +static void doStuff(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); @@ -294,15 +317,16 @@ static void doStuff(struct dds_security_fsm *fsm, void *arg) { } visited_test |= 1UL << 2; - if (do_stuff_counter == 0) { - dds_security_fsm_dispatch(fsm, eventZ); + if (do_stuff_counter < 2) { + dds_security_fsm_dispatch(fsm, eventZ, false); } else if (do_stuff_counter == 2) { - dds_security_fsm_dispatch(fsm, eventY); + dds_security_fsm_dispatch(fsm, eventY, false); } ++do_stuff_counter; } -static void doOtherStuff(struct dds_security_fsm *fsm, void *arg) { +static void doOtherStuff(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); @@ -311,43 +335,54 @@ static void doOtherStuff(struct dds_security_fsm *fsm, void *arg) { } visited_test |= 1UL << 3; if (do_other_stuff_counter == 0) { - dds_security_fsm_dispatch(fsm, DDS_SECURITY_FSM_EVENT_AUTO); + dds_security_fsm_dispatch(fsm, DDS_SECURITY_FSM_EVENT_AUTO, false); } + if (do_other_stuff_counter == 1) { - dds_security_fsm_dispatch(fsm, eventY); + dds_security_fsm_dispatch(fsm, eventY, false); } else if (do_other_stuff_counter == 2) { - dds_security_fsm_dispatch(fsm, eventX); + dds_security_fsm_dispatch(fsm, eventX, false); } ++do_other_stuff_counter; } -dds_security_fsm_state StateA = {doStuff, 0}; -dds_security_fsm_state StateB = {doStuff, 100000000}; -dds_security_fsm_state StateC = {NULL, 0}; -dds_security_fsm_state StateD = {doOtherStuff, 0}; +static dds_security_fsm_state StateA = {doStuff, 0}; +static dds_security_fsm_state StateB = {doStuff, 100000000}; +static dds_security_fsm_state StateC = {NULL, 0}; +static dds_security_fsm_state StateD = {doOtherStuff, 0}; -dds_security_fsm_transition transitions[] = { - {NULL, DDS_SECURITY_FSM_EVENT_AUTO, doStart, &StateA}, // NULL state is the start state - {&StateA, eventZ, NULL, &StateB}, - {&StateA, eventY, doOtherStuff, &StateC}, - {&StateB, eventX, NULL, NULL}, // Reaching NULL means end of state-diagram - {&StateB, eventZ, doRestart, &StateA}, - {&StateC, DDS_SECURITY_FSM_EVENT_AUTO, - doEventStuff, &StateD}, - {&StateD, eventY, doEventStuff, &StateD}, - { - &StateD, eventX, doStuff, NULL}, // Reaching NULL means end of state-diagram +static dds_security_fsm_transition Transitions[] = { + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, doStart, &StateA}, // NULL state is the start state + {&StateA, eventZ, NULL, &StateB}, + {&StateA, eventY, doOtherStuff, &StateC}, + {&StateB, eventX, NULL, NULL}, // Reaching NULL means end of state-diagram + {&StateB, eventZ, doRestart, &StateA}, + {&StateC, DDS_SECURITY_FSM_EVENT_AUTO, doEventStuff, &StateD}, + {&StateD, eventY, doEventStuff, &StateD}, + {&StateD, eventX, doStuff, NULL}, // Reaching NULL means end of sttimeoutate-diagram }; +static const uint32_t TransitionsSize = sizeof(Transitions)/sizeof(Transitions[0]); -/* + +/********************************************************************** * Timeout State Machine properties and methods - */ + **********************************************************************/ + typedef enum { eventToTimeout, eventToEnd, } timeout_events; -/* The functions callld from the state-machine. */ -static void doInterupt(struct dds_security_fsm *fsm, void *arg) { +static struct dds_security_fsm *fsm_timeout; +static uint32_t visited_timeout = 0; +static uint32_t correct_fsm_timeout = 0; +static uint32_t correct_arg_timeout = 0; +static ddsrt_cond_t stop_timeout_cond; +static ddsrt_mutex_t stop_timeout_cond_mutex; +static uint32_t stop_timeout_cond_cnt = 0; + +/* The functions called from the state-machine. */ +static void doInterupt(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) { @@ -356,7 +391,8 @@ static void doInterupt(struct dds_security_fsm *fsm, void *arg) { visited_timeout |= 1UL << 0; } -static void doTimeout(struct dds_security_fsm *fsm, void *arg) { +static void doTimeout(struct dds_security_fsm *fsm, void *arg) +{ dds_duration_t delay4 = 4 * DDS_NSECS_IN_SEC; DDSRT_UNUSED_ARG(arg); @@ -377,10 +413,11 @@ static void doTimeout(struct dds_security_fsm *fsm, void *arg) { printf("Transition <<<< %s %d\n", __FUNCTION__, stop_timeout_cond_cnt); } - dds_security_fsm_dispatch(fsm, eventToTimeout); + dds_security_fsm_dispatch(fsm, eventToTimeout, false); } -static void TimeoutCallback(struct dds_security_fsm *fsm, void *arg) { +static void TimeoutCallback(struct dds_security_fsm *fsm, void *arg) +{ int *fsm_arg; if (DB_TC_PRINT_DEBUG) { @@ -405,7 +442,8 @@ static void TimeoutCallback(struct dds_security_fsm *fsm, void *arg) { } } -static void TimeoutCallback2(struct dds_security_fsm *fsm, void *arg) { +static void TimeoutCallback2(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) { @@ -414,86 +452,121 @@ static void TimeoutCallback2(struct dds_security_fsm *fsm, void *arg) { visited_timeout |= 1UL << 3; } -dds_security_fsm_state StateTimeout = {doTimeout, 0}; -dds_security_fsm_state StateInterupt = {doInterupt, 0}; +static dds_security_fsm_state StateTimeout = {doTimeout, 0};static int fsm_arg = FSM_AUTH_ARG; -dds_security_fsm_transition timeout_transitions[] = {{NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, - &StateTimeout}, // NULL state is the start state - {&StateTimeout, eventToTimeout, NULL, &StateInterupt}, - {&StateInterupt, - eventToEnd, NULL, NULL}, // Reaching NULL means end of state-diagram +static dds_security_fsm_state StateInterupt = {doInterupt, 0}; + +static const dds_security_fsm_transition TimeoutTransitions[] = { + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &StateTimeout}, // NULL state is the start state + {&StateTimeout, eventToTimeout, NULL, &StateInterupt}, + {&StateInterupt,eventToEnd, NULL, NULL}, // Reaching NULL means end of state-diagram }; +static const uint32_t TimeoutTransitionsSize = sizeof(TimeoutTransitions)/sizeof(TimeoutTransitions[0]); + + +/********************************************************************** + * Parallel Timeout State Machines properties and methods + **********************************************************************/ + +static struct dds_security_fsm *fsm_timeout1; +static struct dds_security_fsm *fsm_timeout2; +static struct dds_security_fsm *fsm_timeout3; static dds_time_t time0 = 0; static dds_time_t time1 = 0; static dds_time_t time2 = 0; static dds_time_t time3 = 0; -static void StateParTime1(struct dds_security_fsm *fsm, void *arg) { +static void StateParTime1(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); time1 = dds_time(); } -static void StateParTime2(struct dds_security_fsm *fsm, void *arg) { +static void StateParTime2(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); time2 = dds_time(); } -static void StateParTime3(struct dds_security_fsm *fsm, void *arg) { +static void StateParTime3(struct dds_security_fsm *fsm, void *arg) +{ DDSRT_UNUSED_ARG(fsm); DDSRT_UNUSED_ARG(arg); time3 = dds_time(); } -dds_security_fsm_state StateParTimeout1 = {NULL, DDS_NSECS_IN_SEC}; -dds_security_fsm_state StateParTimeout2 = {NULL, 2 * DDS_NSECS_IN_SEC}; -dds_security_fsm_state StateParTimeout3 = {NULL, DDS_NSECS_IN_SEC}; +static dds_security_fsm_state StateParTimeout1 = {NULL, DDS_SECS(1)}; +static dds_security_fsm_state StateParTimeout2 = {NULL, DDS_SECS(2)}; +static dds_security_fsm_state StateParTimeout3 = {NULL, DDS_SECS(1)}; -dds_security_fsm_transition par_timeout_transitions_1[] = {{NULL, DDS_SECURITY_FSM_EVENT_AUTO, - NULL, &StateParTimeout1}, // NULL state is the start state - {&StateParTimeout1, DDS_SECURITY_FSM_EVENT_TIMEOUT, &StateParTime1, NULL}, // Reaching NULL means end of state-diagram +static dds_security_fsm_transition ParallelTimeoutTransitions_1[] = { + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &StateParTimeout1}, // NULL state is the startfsm_control_thread state + {&StateParTimeout1, DDS_SECURITY_FSM_EVENT_TIMEOUT, &StateParTime1, NULL}, // Reaching NULL means end of state-diagram }; +static const uint32_t ParallelTimeoutTransitionsSize_1 = sizeof(ParallelTimeoutTransitions_1) / sizeof(ParallelTimeoutTransitions_1[0]); -dds_security_fsm_transition par_timeout_transitions_2[] = {{NULL, DDS_SECURITY_FSM_EVENT_AUTO, - NULL, &StateParTimeout2}, // NULL state is the start state - {&StateParTimeout2, DDS_SECURITY_FSM_EVENT_TIMEOUT, &StateParTime2, NULL}, // Reaching NULL means end of state-diagram +static dds_security_fsm_transition ParallelTimeoutTransitions_2[] = { + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &StateParTimeout2}, // NULL state is the start state + {&StateParTimeout2, DDS_SECURITY_FSM_EVENT_TIMEOUT, &StateParTime2, NULL}, // Reaching NULL means end of state-diagram }; +static const uint32_t ParallelTimeoutTransitionsSize_2 = sizeof(ParallelTimeoutTransitions_2) / sizeof(ParallelTimeoutTransitions_2[0]); -dds_security_fsm_transition par_timeout_transitions_3[] = {{NULL, DDS_SECURITY_FSM_EVENT_AUTO, - NULL, &StateParTimeout3}, // NULL state is the start state - {&StateParTimeout3, DDS_SECURITY_FSM_EVENT_TIMEOUT, &StateParTime3, NULL}, // Reaching NULL means end of state-diagram +static dds_security_fsm_transition ParallelTimeoutTransitions_3[] = { + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &StateParTimeout3}, // NULL state is the start state + {&StateParTimeout3, DDS_SECURITY_FSM_EVENT_TIMEOUT, &StateParTime3, NULL}, // Reaching NULL means end of state-diagram }; +static const uint32_t ParallelTimeoutTransitionsSize_3 = sizeof(ParallelTimeoutTransitions_3) / sizeof(ParallelTimeoutTransitions_3[0]); -int fsm_arg = FSM_AUTH_ARG; -dds_time_t delay1 = DDS_NSECS_IN_SEC; -dds_time_t delay2 = 2 * DDS_NSECS_IN_SEC; -dds_time_t delay30 = 30 * DDS_NSECS_IN_SEC; -int timeout; -static const dds_duration_t msec100 = 100 * DDS_NSECS_IN_MSEC; -static void init_testcase(void) { - (void) ddsrt_mutex_init(&stop_timeout_cond_mutex); - (void) ddsrt_cond_init(&stop_timeout_cond); + +static void fsm_control_init(void) +{ + dds_return_t rc; + struct dds_entity *e; + + g_participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL(g_participant > 0); + + rc = dds_entity_pin(g_participant, &e); + CU_ASSERT_FATAL(rc == 0); + + g_fsm_control = dds_security_fsm_control_create (&e->m_domain->gv); + CU_ASSERT_FATAL (g_fsm_control != NULL); + + dds_entity_unpin (e); + + rc = dds_security_fsm_control_start (g_fsm_control, NULL); + CU_ASSERT_FATAL(rc == 0); + + ddsrt_mutex_init(&stop_timeout_cond_mutex); + ddsrt_cond_init(&stop_timeout_cond); } -static void fini_testcase(void) { +static void fsm_control_fini(void) +{ ddsrt_cond_destroy(&stop_timeout_cond); ddsrt_mutex_destroy(&stop_timeout_cond_mutex); + + dds_security_fsm_control_stop(g_fsm_control); + dds_security_fsm_control_free(g_fsm_control); + + dds_delete(g_participant); } -CU_Test(ddssec_fsm, create, .init = init_testcase, .fini = fini_testcase) { +CU_Test(ddssec_fsm, create, .init = fsm_control_init, .fini = fsm_control_fini) +{ + dds_time_t delay30 = DDS_SECS(30); + int timeout; /* * Test single running state machine * Check creation of a single State Machine */ - - fsm_auth = dds_security_fsm_create(NULL, HandshakeTransistions, - sizeof(HandshakeTransistions) / sizeof(HandshakeTransistions[0]), - &fsm_arg); + fsm_auth = dds_security_fsm_create(g_fsm_control, HandshakeTransistions, HandshakeTransistionsSize, &fsm_arg); CU_ASSERT_FATAL(fsm_auth != NULL) // set a delay that doesn't expire. Should be terminate when fsm is freed. @@ -506,21 +579,20 @@ CU_Test(ddssec_fsm, create, .init = init_testcase, .fini = fini_testcase) { // Wait for the last state to occur timeout = 100; /* 10 sec */ - while ((dds_security_fsm_current_state(fsm_auth) != &StateHandshakeInitMessageWait) - && (timeout > 0)) { + while ((dds_security_fsm_current_state(fsm_auth) != &StateHandshakeInitMessageWait) && (timeout > 0)) { dds_sleepfor(msec100); timeout--; } CU_ASSERT(timeout > 0); - dds_security_fsm_dispatch(fsm_auth, SHM_MSG_RECEIVED); + dds_security_fsm_dispatch(fsm_auth, SHM_MSG_RECEIVED, false); timeout = 100; /* 10 sec */ while ((dds_security_fsm_current_state(fsm_auth) != NULL) && (timeout > 0)) { dds_sleepfor(msec100); timeout--; } - CU_ASSERT(timeout > 0); + CU_ASSERT( CHECK_BIT(visited_auth, 0) && CHECK_BIT(visited_auth, 1) && CHECK_BIT(visited_auth, 2) && CHECK_BIT(visited_auth, 3) && CHECK_BIT(visited_auth, 4) && CHECK_BIT(visited_auth, 5) && @@ -539,54 +611,61 @@ CU_Test(ddssec_fsm, create, .init = init_testcase, .fini = fini_testcase) { /* * Test multiple (2) running state machines */ -CU_Test(ddssec_fsm, multiple, .init = init_testcase, .fini = fini_testcase) { +CU_Test(ddssec_fsm, multiple, .init = fsm_control_init, .fini = fsm_control_fini) +{ + int timeout; /*Check creation of multiple (2) State Machines*/ validate_remote_identity_first = 0; begin_handshake_reply_first = 0; visited_auth = 0; + visited_test = 0; + + fsm_auth = dds_security_fsm_create(g_fsm_control, HandshakeTransistions, HandshakeTransistionsSize, NULL); + CU_ASSERT_FATAL(fsm_auth != NULL); + + fsm_test = dds_security_fsm_create(g_fsm_control, Transitions, TransitionsSize, NULL); + CU_ASSERT_FATAL(fsm_test != NULL); - fsm_auth = dds_security_fsm_create(NULL, HandshakeTransistions, - sizeof(HandshakeTransistions) / sizeof(HandshakeTransistions[0]), NULL); - fsm_test = dds_security_fsm_create(NULL, transitions, - sizeof(transitions) / sizeof(transitions[0]), NULL); - CU_ASSERT_FALSE(fsm_auth == NULL || fsm_test == NULL); dds_security_fsm_start(fsm_auth); dds_security_fsm_start(fsm_test); - /*Check the results of multiple running State Machines */ + /* Check the results of multiple running State Machines */ - // Wait for the last state to occur + /* Wait for the last state to occur */ timeout = 100; /* 10 sec */ - while ((dds_security_fsm_current_state(fsm_auth) != &StateHandshakeInitMessageWait) - && (timeout > 0)) { + while ((dds_security_fsm_current_state(fsm_auth) != &StateHandshakeInitMessageWait) && (timeout > 0)) { dds_sleepfor(100 * DDS_NSECS_IN_MSEC); timeout--; } CU_ASSERT_FATAL(timeout > 0); + timeout = 100; /* 10 sec */ - dds_security_fsm_dispatch(fsm_auth, SHM_MSG_RECEIVED); + dds_security_fsm_dispatch(fsm_auth, SHM_MSG_RECEIVED, false); while ((dds_security_fsm_current_state(fsm_auth) != NULL) && (timeout > 0)) { dds_sleepfor(100 * DDS_NSECS_IN_MSEC); timeout--; } CU_ASSERT_FATAL(timeout > 0); + // not all bits are set since we're running the state machine a second time CU_ASSERT_FATAL( CHECK_BIT(visited_auth, 0) && !CHECK_BIT(visited_auth, 1) && CHECK_BIT(visited_auth, 2) && !CHECK_BIT(visited_auth, 3) && CHECK_BIT(visited_auth, 4) && !CHECK_BIT(visited_auth, 5) && CHECK_BIT(visited_auth, 6) && !CHECK_BIT(visited_auth, 7)); + /* Wait for the last state to occur */ timeout = 100; /* 10 sec */ - // Wait for the last state to occur while ((dds_security_fsm_current_state(fsm_test) != NULL) && timeout > 0) { dds_sleepfor(100 * DDS_NSECS_IN_MSEC); timeout--; } CU_ASSERT_FATAL(timeout > 0); - CU_ASSERT_FATAL( + + CU_ASSERT( CHECK_BIT(visited_test, 0) && CHECK_BIT(visited_test, 1) && CHECK_BIT(visited_test, 2) && CHECK_BIT(visited_test, 3)); + dds_security_fsm_free(fsm_auth); dds_security_fsm_free(fsm_test); @@ -595,13 +674,15 @@ CU_Test(ddssec_fsm, multiple, .init = init_testcase, .fini = fini_testcase) { /** * Check creation of State Machine for timeout purposes */ -CU_Test(ddssec_fsm, timeout, .init = init_testcase, .fini = fini_testcase) { +CU_Test(ddssec_fsm, timeout, .init = fsm_control_init, .fini = fsm_control_fini) +{ + dds_time_t delay1 = DDS_SECS(1); + int timeout; /* * Test timeout monitoring of state machines */ - fsm_timeout = dds_security_fsm_create(NULL, timeout_transitions, - sizeof(timeout_transitions) / sizeof(timeout_transitions[0]), &fsm_arg); + fsm_timeout = dds_security_fsm_create(g_fsm_control, TimeoutTransitions, TimeoutTransitionsSize, &fsm_arg); CU_ASSERT(fsm_timeout != NULL); dds_security_fsm_set_timeout(fsm_timeout, TimeoutCallback, delay1); @@ -627,15 +708,19 @@ CU_Test(ddssec_fsm, timeout, .init = init_testcase, .fini = fini_testcase) { /** * Check the double global timeout */ -CU_Test(ddssec_fsm, double_timeout, .init = init_testcase, .fini = fini_testcase) { +CU_Test(ddssec_fsm, double_timeout, .init = fsm_control_init, .fini = fsm_control_fini) +{ + dds_time_t delay1 = DDS_SECS(1); + dds_time_t delay2 = DDS_SECS(2); + int timeout; visited_timeout = 0; - fsm_timeout = dds_security_fsm_create(NULL, timeout_transitions, - sizeof(timeout_transitions) / sizeof(timeout_transitions[0]), &fsm_arg); + fsm_timeout = dds_security_fsm_create(g_fsm_control, TimeoutTransitions, TimeoutTransitionsSize, &fsm_arg); CU_ASSERT(fsm_timeout != NULL); - fsm_timeout2 = dds_security_fsm_create(NULL, timeout_transitions, - sizeof(timeout_transitions) / sizeof(timeout_transitions[0]), &fsm_arg); + + fsm_timeout2 = dds_security_fsm_create(g_fsm_control, TimeoutTransitions, TimeoutTransitionsSize, &fsm_arg); CU_ASSERT(fsm_timeout2 != NULL); + dds_security_fsm_set_timeout(fsm_timeout, TimeoutCallback, delay1); dds_security_fsm_set_timeout(fsm_timeout2, TimeoutCallback2, delay2); dds_security_fsm_start(fsm_timeout); @@ -646,7 +731,7 @@ CU_Test(ddssec_fsm, double_timeout, .init = init_testcase, .fini = fini_testcase timeout--; } CU_ASSERT(CHECK_BIT(visited_timeout, 2)); - dds_security_fsm_cleanup(fsm_timeout); +// dds_security_fsm_cleanup(fsm_timeout); timeout = 100; /* 10 sec */ while ((CHECK_BIT(visited_timeout, 3) == 0) && (timeout > 0)) { dds_sleepfor(100 * DDS_NSECS_IN_MSEC); @@ -664,40 +749,41 @@ CU_Test(ddssec_fsm, double_timeout, .init = init_testcase, .fini = fini_testcase /** * Check parallel state timeouts */ -CU_Test(ddssec_fsm, parallel_timeout, .init = init_testcase, .fini = fini_testcase) { - visited_timeout = 0; - fsm_timeout = dds_security_fsm_create(NULL, par_timeout_transitions_1, - sizeof(par_timeout_transitions_1) / sizeof(par_timeout_transitions_1[0]), - &fsm_arg); - CU_ASSERT(fsm_timeout != NULL); - fsm_timeout2 = dds_security_fsm_create(NULL, par_timeout_transitions_2, - sizeof(par_timeout_transitions_2) / sizeof(par_timeout_transitions_2[0]), - &fsm_arg); - CU_ASSERT(fsm_timeout2 != NULL); - fsm_timeout3 = dds_security_fsm_create(NULL, par_timeout_transitions_3, - sizeof(par_timeout_transitions_3) / sizeof(par_timeout_transitions_3[0]), - &fsm_arg); - CU_ASSERT(fsm_timeout3 != NULL); +CU_Test(ddssec_fsm, parallel_timeout, .init = fsm_control_init, .fini = fsm_control_fini) +{ dds_duration_t delta1; dds_duration_t delta2; dds_duration_t delta3; + int timeout; + + visited_timeout = 0; + + fsm_timeout1 = dds_security_fsm_create(g_fsm_control, ParallelTimeoutTransitions_1, ParallelTimeoutTransitionsSize_1, &fsm_arg); + CU_ASSERT_FATAL(fsm_timeout1 != NULL); + + fsm_timeout2 = dds_security_fsm_create(g_fsm_control, ParallelTimeoutTransitions_2, ParallelTimeoutTransitionsSize_2, &fsm_arg); + CU_ASSERT_FATAL(fsm_timeout2 != NULL); + + fsm_timeout3 = dds_security_fsm_create(g_fsm_control, ParallelTimeoutTransitions_3, ParallelTimeoutTransitionsSize_3, &fsm_arg); + CU_ASSERT_FATAL(fsm_timeout3 != NULL); time0 = dds_time(); - dds_security_fsm_start(fsm_timeout); + dds_security_fsm_start(fsm_timeout1); dds_security_fsm_start(fsm_timeout2); dds_security_fsm_start(fsm_timeout3); /* Wait for both to end. */ - timeout = 100; /* 10 sec */ + timeout = 300; /* 10 sec */ /* First, they have to be started. */ - while (((dds_security_fsm_current_state(fsm_timeout) == NULL) + while (((dds_security_fsm_current_state(fsm_timeout1) == NULL) || (dds_security_fsm_current_state(fsm_timeout2) == NULL) || (dds_security_fsm_current_state(fsm_timeout3) == NULL)) && (timeout > 0)) { dds_sleepfor(100 * DDS_NSECS_IN_MSEC); timeout--; } + /* Then, they have to have ended. */ - while (((dds_security_fsm_current_state(fsm_timeout) != NULL) + while (((dds_security_fsm_current_state(fsm_timeout1) != NULL) || (dds_security_fsm_current_state(fsm_timeout2) != NULL) || (dds_security_fsm_current_state(fsm_timeout3) != NULL)) && (timeout > 0)) { dds_sleepfor(100 * DDS_NSECS_IN_MSEC); @@ -727,7 +813,7 @@ CU_Test(ddssec_fsm, parallel_timeout, .init = init_testcase, .fini = fini_testca CU_ASSERT(delta3 > 750 * DDS_NSECS_IN_MSEC); CU_ASSERT(delta3 < 1250 * DDS_NSECS_IN_MSEC); - dds_security_fsm_free(fsm_timeout); + dds_security_fsm_free(fsm_timeout1); dds_security_fsm_free(fsm_timeout2); dds_security_fsm_free(fsm_timeout3); @@ -736,11 +822,13 @@ CU_Test(ddssec_fsm, parallel_timeout, .init = init_testcase, .fini = fini_testca /** * Delete with event timeout */ -CU_Test(ddssec_fsm, delete_with_timeout, .init = init_testcase, .fini = fini_testcase) { +CU_Test(ddssec_fsm, delete_with_timeout, .init = fsm_control_init, .fini = fsm_control_fini) +{ + int timeout; + + fsm_timeout = dds_security_fsm_create(g_fsm_control, TimeoutTransitions, TimeoutTransitionsSize, &fsm_arg); + CU_ASSERT (fsm_timeout != NULL) - fsm_timeout = dds_security_fsm_create(NULL, timeout_transitions, - sizeof(timeout_transitions) / sizeof(timeout_transitions[0]), &fsm_arg); - CU_ASSERT (fsm_timeout != NULL); visited_timeout = 0; dds_security_fsm_start(fsm_timeout);