aboutsummaryrefslogtreecommitdiffstats
path: root/VES5.0/evel/evel-library/code/evel_library/evel_throttle.c
diff options
context:
space:
mode:
authorMarco Platania <platania@research.att.com>2017-05-18 11:09:08 -0400
committerMarco Platania <platania@research.att.com>2017-05-18 11:09:08 -0400
commitfee6de844f9d4c3aad87733734d35df50117b6b0 (patch)
tree3f42567107ac4a10795c8e80c42b479c4502cbda /VES5.0/evel/evel-library/code/evel_library/evel_throttle.c
parentf3fe765461685a753c0f5b061c5c47383c75829f (diff)
Change location of VES5.0 code
Change-Id: If8a1173813eb4d5c14c04b132269696a748505e7 Signed-off-by: Marco Platania <platania@research.att.com>
Diffstat (limited to 'VES5.0/evel/evel-library/code/evel_library/evel_throttle.c')
-rw-r--r--VES5.0/evel/evel-library/code/evel_library/evel_throttle.c2116
1 files changed, 0 insertions, 2116 deletions
diff --git a/VES5.0/evel/evel-library/code/evel_library/evel_throttle.c b/VES5.0/evel/evel-library/code/evel_library/evel_throttle.c
deleted file mode 100644
index 351c7da7..00000000
--- a/VES5.0/evel/evel-library/code/evel_library/evel_throttle.c
+++ /dev/null
@@ -1,2116 +0,0 @@
-/**************************************************************************//**
- * @file
- * Event Manager
- *
- * Simple event manager that is responsible for taking events (Heartbeats,
- * Faults and Measurements) from the ring-buffer and posting them to the API.
- *
- * License
- * -------
- *
- * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement: This product includes
- * software developed by the AT&T.
- * 4. Neither the name of AT&T nor the names of its contributors may be used to
- * endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*****************************************************************************/
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <pthread.h>
-#include <search.h>
-
-#include "evel_throttle.h"
-
-/*****************************************************************************/
-/* The Event Throttling State for all domains, indexed by */
-/* ::EVEL_EVENT_DOMAINS, corresponding to JSON eventDomain. */
-/* */
-/* A given domain is in a throttled state if ::evel_throttle_spec is */
-/* non-NULL. */
-/*****************************************************************************/
-static EVEL_THROTTLE_SPEC * evel_throttle_spec[EVEL_MAX_DOMAINS];
-
-/*****************************************************************************/
-/* The current measurement interval. Default: MEASUREMENT_INTERVAL_UKNOWN. */
-/* Must be protected by evel_measurement_interval_mutex. */
-/*****************************************************************************/
-static int evel_measurement_interval;
-
-/*****************************************************************************/
-/* Mutex protecting evel_measurement_interval from contention between an */
-/* EVEL client reading it, and the EVEL event handler updating it. */
-/*****************************************************************************/
-static pthread_mutex_t evel_measurement_interval_mutex;
-
-/*****************************************************************************/
-/* Flag stating that we have received a "provideThrottlingState" command. */
-/* Set during JSON processing and cleared on sending the throttling state. */
-/*****************************************************************************/
-static bool evel_provide_throttling_state;
-
-/*****************************************************************************/
-/* Holder for the "commandType" value during JSON processing. */
-/*****************************************************************************/
-static char * evel_command_type_value;
-
-/*****************************************************************************/
-/* Holder for the "measurementInterval" value during JSON processing. */
-/*****************************************************************************/
-static char * evel_measurement_interval_value;
-
-/*****************************************************************************/
-/* Holder for the "eventDomain" value during JSON processing. */
-/*****************************************************************************/
-static char * evel_throttle_spec_domain_value;
-
-/*****************************************************************************/
-/* Decoded version of ::evel_throttle_spec_domain_value. */
-/*****************************************************************************/
-static EVEL_EVENT_DOMAINS evel_throttle_spec_domain;
-
-/*****************************************************************************/
-/* During JSON processing of a single throttling specification, we collect */
-/* parameters in this working ::EVEL_THROTTLE_SPEC */
-/*****************************************************************************/
-static EVEL_THROTTLE_SPEC * evel_temp_throttle;
-
-/*****************************************************************************/
-/* State tracking our progress through the command list */
-/*****************************************************************************/
-EVEL_JSON_COMMAND_STATE evel_json_command_state;
-
-/*****************************************************************************/
-/* Debug strings for ::EVEL_JSON_COMMAND_STATE. */
-/*****************************************************************************/
-static const char * const evel_jcs_strings[EVEL_JCS_MAX] = {
- "EVEL_JCS_START",
- "EVEL_JCS_COMMAND_LIST",
- "EVEL_JCS_COMMAND_LIST_ENTRY",
- "EVEL_JCS_COMMAND",
- "EVEL_JCS_SPEC",
- "EVEL_JCS_FIELD_NAMES",
- "EVEL_JCS_PAIRS_LIST",
- "EVEL_JCS_PAIRS_LIST_ENTRY",
- "EVEL_JCS_NV_PAIR_NAMES"
-};
-
-/*****************************************************************************/
-/* Debug strings for JSON token type. */
-/*****************************************************************************/
-#define JSON_TOKEN_TYPES (JSMN_PRIMITIVE + 1)
-static const char * const evel_json_token_strings[JSON_TOKEN_TYPES] = {
- "JSMN_UNDEFINED",
- "JSMN_OBJECT",
- "JSMN_ARRAY",
- "JSMN_STRING",
- "JSMN_PRIMITIVE"
-};
-
-/*****************************************************************************/
-/* Debug strings for JSON domains. */
-/*****************************************************************************/
-static const char * evel_domain_strings[EVEL_MAX_DOMAINS] = {
- "internal",
- "heartbeat",
- "fault",
- "measurementsForVfScaling",
- "mobileFlow",
- "report",
- "serviceEvents",
- "signaling",
- "stateChange",
- "syslog",
- "other"
- "voiceQuality",
- "maxDomain"
-};
-
-/*****************************************************************************/
-/* Local prototypes. */
-/*****************************************************************************/
-static void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec);
-static struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys);
-static void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec);
-static void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
-static void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
- const MEMORY_CHUNK * const chunk);
-static bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
- const int num_required,
- const EVEL_JSON_STATE new_state);
-static void evel_stack_pop(EVEL_JSON_STACK * const json_stack);
-static void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack);
-static char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
- const jsmntok_t * const token);
-static void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
- const jsmntok_t * const token);
-static void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
- const jsmntok_t * const token);
-static void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
- const jsmntok_t * const token);
-static void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state);
-static void evel_debug_token(const MEMORY_CHUNK * const chunk,
- const jsmntok_t * const token);
-static void evel_command_list_response(MEMORY_CHUNK * const post);
-static int evel_json_encode_throttle(char * const json, const int max_size);
-static int evel_json_encode_throttle_spec(char * const json,
- const int max_size,
- const EVEL_EVENT_DOMAINS domain);
-static int evel_json_encode_nv_pairs(char * const json,
- const int max_size,
- EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
-static void evel_close_command();
-static void evel_open_command();
-static void evel_set_throttling_spec();
-static void evel_set_measurement_interval();
-static void evel_open_throttle_spec();
-static void evel_close_throttle_spec();
-static EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value);
-static void evel_open_nv_pairs_list_entry();
-static void evel_close_nv_pairs_list_entry();
-static void evel_store_nv_pair_field_name(char * const value);
-static void evel_store_nv_pair_name(char * const item);
-static void evel_store_suppressed_field_name(char * const item);
-static EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs();
-
-/**************************************************************************//**
- * Return the current measurement interval provided by the Event Listener.
- *
- * @returns The current measurement interval
- * @retval EVEL_MEASUREMENT_INTERVAL_UKNOWN (0) - interval has not been
- * specified
- *****************************************************************************/
-int evel_get_measurement_interval()
-{
- int result;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Lock, read, unlock. */
- /***************************************************************************/
- pthread_mutex_lock(&evel_measurement_interval_mutex);
- result = evel_measurement_interval;
- pthread_mutex_unlock(&evel_measurement_interval_mutex);
-
- EVEL_EXIT();
-
- return result;
-}
-
-/**************************************************************************//**
- * Return the ::EVEL_THROTTLE_SPEC for a given domain.
- *
- * @param domain The domain for which to return state.
- *****************************************************************************/
-EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain)
-{
- EVEL_THROTTLE_SPEC * result;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(domain < EVEL_MAX_DOMAINS);
-
- result = evel_throttle_spec[domain];
-
- EVEL_EXIT();
-
- return result;
-}
-
-/**************************************************************************//**
- * Determine whether a field_name should be suppressed.
- *
- * @param throttle_spec Throttle specification for the domain being encoded.
- * @param field_name The field name to encoded or suppress.
- * @return true if the field_name should be suppressed, false otherwise.
- *****************************************************************************/
-bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC * throttle_spec,
- const char * const field_name)
-{
- bool suppress = false;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(field_name != NULL);
-
- /***************************************************************************/
- /* If the throttle spec and hash table exist, query the field_names table. */
- /***************************************************************************/
- if ((throttle_spec != NULL) && (throttle_spec->hash_field_names != NULL))
- {
- ENTRY hash_query;
- ENTRY * hash_result;
- hash_query.key = (char * const) field_name;
- suppress = (hsearch_r(hash_query,
- FIND,
- &hash_result,
- throttle_spec->hash_field_names) != 0);
- }
-
- EVEL_EXIT();
-
- return suppress;
-}
-
-/**************************************************************************//**
- * Determine whether a name-value pair should be allowed (not suppressed).
- *
- * @param throttle_spec Throttle specification for the domain being encoded.
- * @param field_name The field name holding the name-value pairs.
- * @param name The name of the name-value pair to encoded or suppress.
- * @return true if the name-value pair should be suppressed, false otherwise.
- *****************************************************************************/
-bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC * throttle_spec,
- const char * const field_name,
- const char * const name)
-{
- EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
- bool hit = false;
- bool suppress = false;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(field_name != NULL);
- assert(name != NULL);
-
- /***************************************************************************/
- /* If the throttle spec and hash table exist, query the nv_pairs table. */
- /***************************************************************************/
- if ((throttle_spec != NULL) && (throttle_spec->hash_nv_pairs_list != NULL))
- {
- ENTRY hash_query;
- ENTRY * hash_result;
- hash_query.key = (char * const) field_name;
- hit = (hsearch_r(hash_query,
- FIND,
- &hash_result,
- throttle_spec->hash_nv_pairs_list) != 0);
- if (hit)
- {
- nv_pairs = hash_result->data;
- }
- }
-
- /***************************************************************************/
- /* If we got a hit, and the nv_pairs and hash table exist, query the */
- /* nv_pairs table. */
- /***************************************************************************/
- if (hit && (nv_pairs != NULL) && (nv_pairs->hash_nv_pair_names != NULL))
- {
- ENTRY hash_query;
- ENTRY * hash_result;
- hash_query.key = (char * const) name;
- suppress = (hsearch_r(hash_query,
- FIND,
- &hash_result,
- nv_pairs->hash_nv_pair_names) != 0);
- }
-
- EVEL_EXIT();
-
- return suppress;
-}
-
-/**************************************************************************//**
- * Initialize event throttling to the default state.
- *
- * Called from ::evel_initialize.
- *****************************************************************************/
-void evel_throttle_initialize()
-{
- int pthread_rc;
- int ii;
-
- EVEL_ENTER();
-
- for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
- {
- evel_throttle_spec[ii] = NULL;
- }
-
- pthread_rc = pthread_mutex_init(&evel_measurement_interval_mutex, NULL);
- assert(pthread_rc == 0);
-
- evel_measurement_interval = EVEL_MEASUREMENT_INTERVAL_UKNOWN;
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Clean up event throttling.
- *
- * Called from ::evel_terminate.
- *****************************************************************************/
-void evel_throttle_terminate()
-{
- int pthread_rc;
- int ii;
-
- EVEL_ENTER();
-
- for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
- {
- if (evel_throttle_spec[ii] != NULL)
- {
- evel_throttle_free(evel_throttle_spec[ii]);
- evel_throttle_spec[ii] = NULL;
- }
- }
-
- pthread_rc = pthread_mutex_destroy(&evel_measurement_interval_mutex);
- assert(pthread_rc == 0);
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Finalize a single ::EVEL_THROTTLE_SPEC.
- *
- * Now that the specification is collected, build hash tables to simplify the
- * throttling itself.
- *
- * @param throttle_spec The ::EVEL_THROTTLE_SPEC to finalize.
- *****************************************************************************/
-void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec)
-{
- int nv_pairs_count;
- DLIST_ITEM * dlist_item;
- ENTRY * add_result;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(throttle_spec != NULL);
-
- /***************************************************************************/
- /* Populate the hash table for suppressed field names. */
- /***************************************************************************/
- throttle_spec->hash_field_names =
- evel_throttle_hash_create(&throttle_spec->suppressed_field_names);
-
- /***************************************************************************/
- /* Create the hash table for suppressed nv pairs. */
- /***************************************************************************/
- nv_pairs_count = dlist_count(&throttle_spec->suppressed_nv_pairs_list);
- if (nv_pairs_count > 0)
- {
- throttle_spec->hash_nv_pairs_list = calloc(1, sizeof(struct hsearch_data));
- assert(throttle_spec->hash_nv_pairs_list != NULL);
-
- /*************************************************************************/
- /* Provide plenty of space in the table - see hcreate_r notes. */
- /*************************************************************************/
- if (hcreate_r(nv_pairs_count * 2, throttle_spec->hash_nv_pairs_list) == 0)
- {
- EVEL_ERROR("Failed to create hash table");
- free(throttle_spec->hash_nv_pairs_list);
- throttle_spec->hash_nv_pairs_list = NULL;
- }
- }
-
- /***************************************************************************/
- /* Populate the hash tables under suppressed field names. */
- /***************************************************************************/
- dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
- while (dlist_item != NULL)
- {
- EVEL_SUPPRESSED_NV_PAIRS * nv_pairs = dlist_item->item;
- ENTRY hash_add;
-
- /*************************************************************************/
- /* Set the key to the string, and the item to the nv_pairs. */
- /*************************************************************************/
- assert(nv_pairs != NULL);
- hash_add.key = nv_pairs->nv_pair_field_name;
- hash_add.data = nv_pairs;
- hsearch_r(hash_add, ENTER, &add_result, throttle_spec->hash_nv_pairs_list);
-
- /*************************************************************************/
- /* Create the nv_pair_names hash since we're in here. */
- /*************************************************************************/
- nv_pairs->hash_nv_pair_names =
- evel_throttle_hash_create(&nv_pairs->suppressed_nv_pair_names);
-
- dlist_item = dlist_get_next(dlist_item);
- }
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Create and populate a hash table from a DLIST of keys.
- *
- * @param hash_keys Pointer to a DLIST of hash table keys.
- * @return Pointer to the created hash-table, or NULL on failure.
- *****************************************************************************/
-struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys)
-{
- int key_count;
- struct hsearch_data * hash_table;
- ENTRY * add_result;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(hash_keys != NULL);
-
- /***************************************************************************/
- /* Count the keys and if there are any, populate the hash table with them. */
- /***************************************************************************/
- key_count = dlist_count(hash_keys);
- if (key_count > 0)
- {
- EVEL_DEBUG("Populating table for %d keys", key_count);
-
- hash_table = calloc(1, sizeof(struct hsearch_data));
- assert(hash_table != NULL);
-
- /*************************************************************************/
- /* We need to leave plenty of space in the table - see hcreate_r notes. */
- /*************************************************************************/
- if (hcreate_r(key_count * 2, hash_table) != 0)
- {
- DLIST_ITEM * dlist_item;
- dlist_item = dlist_get_first(hash_keys);
- while (dlist_item != NULL)
- {
- assert(dlist_item->item != NULL);
-
- /*********************************************************************/
- /* Set the key and data to the item, which is a string in this case. */
- /*********************************************************************/
- ENTRY hash_add;
- hash_add.key = dlist_item->item;
- hash_add.data = dlist_item->item;
- hsearch_r(hash_add, ENTER, &add_result, hash_table);
- dlist_item = dlist_get_next(dlist_item);
- }
- }
- else
- {
- EVEL_ERROR("Failed to create hash table");
- free(hash_table);
- hash_table = NULL;
- }
- }
- else
- {
- hash_table = NULL;
- }
-
- EVEL_EXIT();
-
- return hash_table;
-}
-
-/**************************************************************************//**
- * Free resources associated with a single ::EVEL_THROTTLE_SPEC.
- *
- * @param throttle_spec The ::EVEL_THROTTLE_SPEC to free.
- *****************************************************************************/
-void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec)
-{
- char * field_name;
- EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(throttle_spec != NULL);
-
- /***************************************************************************/
- /* Free any hash tables. */
- /***************************************************************************/
- if (throttle_spec->hash_field_names != NULL)
- {
- hdestroy_r(throttle_spec->hash_field_names);
- free(throttle_spec->hash_field_names);
- }
- if (throttle_spec->hash_nv_pairs_list != NULL)
- {
- hdestroy_r(throttle_spec->hash_nv_pairs_list);
- free(throttle_spec->hash_nv_pairs_list);
- }
-
- /***************************************************************************/
- /* Iterate through the linked lists, freeing memory. */
- /***************************************************************************/
- field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
- while (field_name != NULL)
- {
- free(field_name);
- field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
- }
-
- nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
- while (nv_pairs != NULL)
- {
- evel_throttle_free_nv_pair(nv_pairs);
- nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
- }
-
- free(throttle_spec);
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Free resources associated with a single ::EVEL_SUPPRESSED_NV_PAIR.
- *
- * @param nv_pair The ::EVEL_SUPPRESSED_NV_PAIR to free.
- *****************************************************************************/
-void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
-{
- char * suppressed_name;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(nv_pairs != NULL);
-
- /***************************************************************************/
- /* Free any hash tables. */
- /***************************************************************************/
- if (nv_pairs->hash_nv_pair_names != NULL)
- {
- hdestroy_r(nv_pairs->hash_nv_pair_names);
- free(nv_pairs->hash_nv_pair_names);
- }
-
- /***************************************************************************/
- /* Iterate through the linked lists, freeing memory. */
- /***************************************************************************/
- suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
- while (suppressed_name != NULL)
- {
- free(suppressed_name);
- suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
- }
- if (nv_pairs->nv_pair_field_name != NULL)
- {
- free(nv_pairs->nv_pair_field_name);
- }
- free(nv_pairs);
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Handle a JSON response from the listener, as a list of tokens from JSMN.
- *
- * @param chunk Memory chunk containing the JSON buffer.
- * @param json_tokens Array of tokens to handle.
- * @param num_tokens The number of tokens to handle.
- * @param post The memory chunk in which to place any resulting POST.
- * @return true if the command was handled, false otherwise.
- *****************************************************************************/
-bool evel_handle_command_list(const MEMORY_CHUNK * const chunk,
- const jsmntok_t * const json_tokens,
- const int num_tokens,
- MEMORY_CHUNK * const post)
-{
- EVEL_JSON_STACK stack;
- EVEL_JSON_STACK * json_stack = &stack;
- EVEL_JSON_STACK_ENTRY * entry;
-
- bool json_ok = true;
- int token_index = 0;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(chunk != NULL);
- assert(json_tokens != NULL);
- assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS);
-
- /***************************************************************************/
- /* Collect one top-level item. */
- /***************************************************************************/
- evel_init_json_stack(json_stack, chunk);
-
- /***************************************************************************/
- /* Initialize JSON processing variables. */
- /***************************************************************************/
- evel_provide_throttling_state = false;
- evel_command_type_value = NULL;
- evel_measurement_interval_value = NULL;
- evel_throttle_spec_domain_value = NULL;
- evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
- evel_temp_throttle = NULL;
- evel_json_command_state = EVEL_JCS_START;
-
- /***************************************************************************/
- /* Loop through the tokens, keeping a stack of state representing the */
- /* nested JSON structure (see json_state). We also track our way through */
- /* the ::EVEL_JSON_COMMAND_STATE as we go. */
- /***************************************************************************/
- while (json_ok && (token_index < num_tokens))
- {
- const jsmntok_t * const token = &json_tokens[token_index];
-
- if (EVEL_DEBUG_ON())
- {
- evel_debug_token(chunk, token);
- }
-
- /*************************************************************************/
- /* We may have popped or pushed, so always re-evaluate the stack entry. */
- /*************************************************************************/
- entry = &json_stack->entry[json_stack->level];
-
- switch(token->type)
- {
- case JSMN_OBJECT:
- if ((entry->json_state == EVEL_JSON_ITEM) ||
- (entry->json_state == EVEL_JSON_VALUE))
- {
- json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_KEY);
- }
- else
- {
- EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
- entry->json_state, token_index, token->type);
- json_ok = false;
- }
- break;
-
- case JSMN_ARRAY:
- if ((entry->json_state == EVEL_JSON_ITEM) ||
- (entry->json_state == EVEL_JSON_VALUE))
- {
- json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_ITEM);
- }
- else
- {
- EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
- entry->json_state, token_index, token->type);
- json_ok = false;
- }
- break;
-
- case JSMN_STRING:
- if (entry->json_state == EVEL_JSON_KEY)
- {
- evel_stack_store_key(json_stack, token);
- }
- else if (entry->json_state == EVEL_JSON_VALUE)
- {
- evel_stack_store_value(json_stack, token);
- }
- else if (entry->json_state == EVEL_JSON_ITEM)
- {
- evel_stack_store_item(json_stack, token);
- }
- else
- {
- EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
- entry->json_state, token_index, token->type);
- json_ok = false;
- }
- break;
-
- case JSMN_PRIMITIVE:
- if (entry->json_state == EVEL_JSON_VALUE)
- {
- evel_stack_store_value(json_stack, token);
- }
- else if (entry->json_state == EVEL_JSON_ITEM)
- {
- evel_stack_store_item(json_stack, token);
- }
- else
- {
- EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
- entry->json_state, token_index, token->type);
- json_ok = false;
- }
- break;
-
- case JSMN_UNDEFINED:
- default:
- EVEL_ERROR("Unexpected JSON format at token %d (%d)",
- token_index, token->type);
- json_ok = false;
- break;
- }
-
- /*************************************************************************/
- /* Pop the stack if we're counted enough nested items. */
- /*************************************************************************/
- evel_stack_pop(json_stack);
-
- token_index++;
- }
-
- /***************************************************************************/
- /* Cleanup the stack - we may have exited without winding it back, if the */
- /* input was not well formed. */
- /***************************************************************************/
- evel_stack_cleanup(json_stack);
-
- /***************************************************************************/
- /* We may want to generate and POST a response to the command list. */
- /***************************************************************************/
- if (json_ok)
- {
- evel_command_list_response(post);
- }
-
- /***************************************************************************/
- /* Make sure we're clean on exit. */
- /***************************************************************************/
- assert(evel_command_type_value == NULL);
- assert(evel_measurement_interval_value == NULL);
- assert(evel_throttle_spec_domain_value == NULL);
- assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
- assert(evel_temp_throttle == NULL);
-
- EVEL_EXIT();
-
- return json_ok;
-}
-
-/**************************************************************************//**
- * Copy a copy of an element, in string form.
- *
- * The caller must manage memory allocated for the copied string.
- *
- * @param chunk Memory chunk containing the JSON buffer.
- * @param token The token to copy from.
- * @return the copy of the element.
- *****************************************************************************/
-char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
- const jsmntok_t * const token)
-{
- char temp_char;
- char * result;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Call strdup to copy the string, inserting a temporary \0 for the call. */
- /***************************************************************************/
- temp_char = chunk->memory[token->end];
- chunk->memory[token->end] = '\0';
- result = strdup(chunk->memory + token->start);
- assert(result != NULL);
- chunk->memory[token->end] = temp_char;
-
- EVEL_EXIT();
-
- return result;
-}
-
-/**************************************************************************//**
- * Copy a copy of an element, in string form.
- *
- * @param json_stack The JSON stack to initialize.
- * @param chunk The underlying memory chunk used for parsing.
- *****************************************************************************/
-void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
- const MEMORY_CHUNK * const chunk)
-{
- EVEL_JSON_STACK_ENTRY * entry;
-
- EVEL_ENTER();
-
- json_stack->level = 0;
- entry = json_stack->entry;
- entry->json_state = EVEL_JSON_ITEM;
- entry->json_count = 0;
- entry->num_required = 1;
- entry->json_key = NULL;
- json_stack->chunk = chunk;
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Push a new entry on the stack
- *
- * @param json_stack The stack.
- * @param num_required The number of elements required.
- * @param new_state The state for the new entry.
- * @return false if we cannot push onto the stack.
- *****************************************************************************/
-bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
- const int num_required,
- const EVEL_JSON_STATE new_state)
-{
- EVEL_JSON_STACK_ENTRY * entry;
- char * key;
- bool result;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(json_stack != NULL);
- assert(json_stack->level >= 0);
- assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
- assert((new_state == EVEL_JSON_ITEM) || (new_state == EVEL_JSON_KEY));
-
- /***************************************************************************/
- /* Check nesting depth, and stop processing if we hit the limit. */
- /***************************************************************************/
- if ((json_stack->level + 1) >= EVEL_JSON_STACK_DEPTH)
- {
- EVEL_ERROR("JSON Nesting is too deep - stop processing");
- result = false;
- goto exit_label;
- }
-
- /***************************************************************************/
- /* Evaluate cases where we recurse and are interested in the contents. */
- /***************************************************************************/
- entry = &json_stack->entry[json_stack->level];
- key = entry->json_key;
-
- /***************************************************************************/
- /* Note that this is the key before we drop a level. */
- /***************************************************************************/
- if (key != NULL)
- {
- EVEL_DEBUG("Push with key: %s", key);
-
- switch (evel_json_command_state)
- {
- case EVEL_JCS_START:
- if (strcmp(key, "commandList") == 0)
- {
- evel_set_command_state(EVEL_JCS_COMMAND_LIST);
- }
- break;
-
- case EVEL_JCS_COMMAND_LIST_ENTRY:
- if (strcmp(key, "command") == 0)
- {
- evel_open_command();
- evel_set_command_state(EVEL_JCS_COMMAND);
- }
- break;
-
- case EVEL_JCS_COMMAND:
- if (strcmp(key, "eventDomainThrottleSpecification") == 0)
- {
- evel_open_throttle_spec();
- evel_set_command_state(EVEL_JCS_SPEC);
- }
- break;
-
- case EVEL_JCS_SPEC:
- if (strcmp(key, "suppressedFieldNames") == 0)
- {
- evel_set_command_state(EVEL_JCS_FIELD_NAMES);
- }
- else if (strcmp(key, "suppressedNvPairsList") == 0)
- {
- evel_set_command_state(EVEL_JCS_PAIRS_LIST);
- }
- break;
-
- case EVEL_JCS_PAIRS_LIST_ENTRY:
- if (strcmp(key, "suppressedNvPairNames") == 0)
- {
- evel_set_command_state(EVEL_JCS_NV_PAIR_NAMES);
- }
- break;
-
- case EVEL_JCS_FIELD_NAMES:
- case EVEL_JCS_PAIRS_LIST:
- case EVEL_JCS_NV_PAIR_NAMES:
- default:
- EVEL_ERROR("Unexpected JSON key %s in state %d",
- key,
- evel_json_command_state);
- break;
- }
- }
- else
- {
- EVEL_DEBUG("Push with no key");
-
- /*************************************************************************/
- /* If we're pushing without a key, then we're in an array. We switch */
- /* state based on the existing state and stack level. */
- /*************************************************************************/
- const int COMMAND_LIST_LEVEL = 2;
- const int NV_PAIRS_LIST_LEVEL = 6;
-
- if ((evel_json_command_state == EVEL_JCS_PAIRS_LIST) &&
- (json_stack->level == NV_PAIRS_LIST_LEVEL))
- {
- /***********************************************************************/
- /* We are entering an object within the "suppressedNvPairsList" array. */
- /***********************************************************************/
- evel_open_nv_pairs_list_entry();
- evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
- }
-
- if ((evel_json_command_state == EVEL_JCS_COMMAND_LIST) &&
- (json_stack->level == COMMAND_LIST_LEVEL))
- {
- /***********************************************************************/
- /* We are entering an object within the "commandList" array. */
- /***********************************************************************/
- evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
- }
- }
-
- /***************************************************************************/
- /* Push the stack and initialize the entry. */
- /***************************************************************************/
- json_stack->level++;
- entry++;
- EVEL_DEBUG("Stack Push -> %d", json_stack->level);
- entry = &json_stack->entry[json_stack->level];
- entry->json_count = 0;
- entry->num_required = num_required;
- entry->json_state = new_state;
- entry->json_key = NULL;
- result = true;
-
-exit_label:
-
- EVEL_EXIT();
-
- return result;
-}
-
-/**************************************************************************//**
- * Pop any stack entries which have collected the required number of items.
- *
- * @param json_stack The stack.
- *****************************************************************************/
-void evel_stack_pop(EVEL_JSON_STACK * const json_stack)
-{
- EVEL_JSON_STACK_ENTRY * entry;
- char * key;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(json_stack != NULL);
- assert(json_stack->level >= 0);
- assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
-
- entry = &json_stack->entry[json_stack->level];
- while ((json_stack->level > 0) && (entry->json_count == entry->num_required))
- {
- key = entry->json_key;
-
- switch (evel_json_command_state)
- {
- case EVEL_JCS_COMMAND_LIST:
- evel_set_command_state(EVEL_JCS_START);
- break;
-
- case EVEL_JCS_COMMAND_LIST_ENTRY:
- evel_set_command_state(EVEL_JCS_COMMAND_LIST);
- break;
-
- case EVEL_JCS_COMMAND:
- evel_close_command();
- evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
- break;
-
- case EVEL_JCS_SPEC:
- evel_close_throttle_spec();
- evel_set_command_state(EVEL_JCS_COMMAND);
- break;
-
- case EVEL_JCS_FIELD_NAMES:
- evel_set_command_state(EVEL_JCS_SPEC);
- break;
-
- case EVEL_JCS_PAIRS_LIST:
- evel_set_command_state(EVEL_JCS_SPEC);
- break;
-
- case EVEL_JCS_PAIRS_LIST_ENTRY:
- evel_close_nv_pairs_list_entry();
- evel_set_command_state(EVEL_JCS_PAIRS_LIST);
- break;
-
- case EVEL_JCS_NV_PAIR_NAMES:
- evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
- break;
-
- default:
- break;
- }
-
- /*************************************************************************/
- /* Free off any key that was duplicated and stored. */
- /*************************************************************************/
- if (key != NULL)
- {
- free(key);
- entry->json_key = NULL;
- }
-
- /*************************************************************************/
- /* We just reached the required number of key-value pairs or items, so */
- /* pop the stack. */
- /*************************************************************************/
- json_stack->level--;
- entry--;
-
- EVEL_DEBUG("Stack Pop -> %d", json_stack->level);
-
- /*************************************************************************/
- /* We just completed collection of an ITEM (within an ARRAY) or a VALUE */
- /* (within an OBJECT). Either way, we need to count it. */
- /*************************************************************************/
- entry->json_count++;
-
- /*************************************************************************/
- /* If we just completed a VALUE, then we expect the next element to be a */
- /* key, if there is a next element. */
- /*************************************************************************/
- if (entry->json_state == EVEL_JSON_VALUE)
- {
- entry->json_state = EVEL_JSON_KEY;
- }
- }
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Pop all stack entries, freeing any memory as we go.
- *
- * @param json_stack The stack.
- *****************************************************************************/
-void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack)
-{
- EVEL_JSON_STACK_ENTRY * entry;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(json_stack != NULL);
- assert(json_stack->level >= 0);
- assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
-
- entry = &json_stack->entry[json_stack->level];
- while ((json_stack->level > 0))
- {
- /*************************************************************************/
- /* Free off any key that was duplicated and stored. */
- /*************************************************************************/
- if (entry->json_key != NULL)
- {
- free(entry->json_key);
- entry->json_key = NULL;
- }
-
- /*************************************************************************/
- /* We just reached the required number of key-value pairs or items, so */
- /* pop the stack. */
- /*************************************************************************/
- json_stack->level--;
- entry--;
- }
-
- /***************************************************************************/
- /* If we hit EVEL_JSON_STACK_DEPTH, we exit the loop and can leave these */
- /* values hanging - so clean them up. */
- /***************************************************************************/
- if (evel_command_type_value != NULL)
- {
- free(evel_command_type_value);
- evel_command_type_value = NULL;
- }
- if (evel_measurement_interval_value != NULL)
- {
- free(evel_measurement_interval_value);
- evel_measurement_interval_value = NULL;
- }
- if (evel_throttle_spec_domain_value != NULL)
- {
- free(evel_throttle_spec_domain_value);
- evel_throttle_spec_domain_value = NULL;
- }
- evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
- if (evel_temp_throttle != NULL)
- {
- evel_throttle_free(evel_temp_throttle);
- evel_temp_throttle = NULL;
- }
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Store a key in the JSON stack.
- *
- * We always store the most recent key at each level in the stack.
- *
- * @param json_stack The stack.
- * @param token The token holding the key.
- *****************************************************************************/
-void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
- const jsmntok_t * const token)
-{
- EVEL_JSON_STACK_ENTRY * entry;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(json_stack != NULL);
- assert(json_stack->level >= 0);
- assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
-
- /***************************************************************************/
- /* Free any previously stored key, replacing it with the new one. */
- /***************************************************************************/
- entry = &json_stack->entry[json_stack->level];
- if (entry->json_key != NULL)
- {
- free(entry->json_key);
- }
- entry->json_key = evel_stack_strdup(json_stack->chunk, token);
-
- /***************************************************************************/
- /* Switch state to collecting the corresponding value. */
- /***************************************************************************/
- entry->json_state = EVEL_JSON_VALUE;
-
- EVEL_DEBUG("Stored key: %s", entry->json_key);
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Store a value in the JSON stack.
- *
- * @param json_stack The stack.
- * @param token The token holding the value.
- *****************************************************************************/
-void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
- const jsmntok_t * const token)
-{
- EVEL_JSON_STACK_ENTRY * entry;
- char * value;
- bool stored;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(json_stack != NULL);
- assert(json_stack->level >= 0);
- assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
-
- /***************************************************************************/
- /* Based on the (key, state), work out whether we're expecting a value, */
- /* then store or ignore it as required. */
- /***************************************************************************/
- entry = &json_stack->entry[json_stack->level];
- value = evel_stack_strdup(json_stack->chunk, token);
- stored = false;
- EVEL_DEBUG("Store value: %s", value);
-
- switch (evel_json_command_state)
- {
- case EVEL_JCS_COMMAND:
- if (strcmp(entry->json_key, "commandType") == 0)
- {
- evel_command_type_value = value;
- stored = true;
- }
- else if (strcmp(entry->json_key, "measurementInterval") == 0)
- {
- evel_measurement_interval_value = value;
- stored = true;
- }
- break;
-
- case EVEL_JCS_SPEC:
- if (strcmp(entry->json_key, "eventDomain") == 0)
- {
- evel_throttle_spec_domain_value = value;
- stored = true;
- }
- break;
-
- case EVEL_JCS_PAIRS_LIST_ENTRY:
- if (strcmp(entry->json_key, "nvPairFieldName") == 0)
- {
- evel_store_nv_pair_field_name(value);
- stored = true;
- }
- break;
-
- default:
- EVEL_DEBUG("Ignoring value in state: %s",
- evel_jcs_strings[evel_json_command_state]);
- break;
- }
-
- if (!stored)
- {
- EVEL_DEBUG("Ignored value: %s", value);
- free(value);
- }
-
- /***************************************************************************/
- /* Switch state to another key. */
- /***************************************************************************/
- entry->json_state = EVEL_JSON_KEY;
-
- /***************************************************************************/
- /* Count the key-value pair. */
- /***************************************************************************/
- entry->json_count++;
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Store an item in the JSON stack - a string or primitive in an array.
- *
- * @param json_stack The stack.
- * @param token The token holding the item.
- *****************************************************************************/
-void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
- const jsmntok_t * const token)
-{
- EVEL_JSON_STACK_ENTRY * entry;
- char * item;
- bool stored;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(json_stack != NULL);
- assert(json_stack->level >= 0);
- assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
-
- /***************************************************************************/
- /* Based on the state, work out whether we're expecting an item, then */
- /* store or ignore it as required. */
- /***************************************************************************/
- entry = &json_stack->entry[json_stack->level];
- item = evel_stack_strdup(json_stack->chunk, token);
- stored = false;
- EVEL_DEBUG("Store item: %s", item);
-
- switch (evel_json_command_state)
- {
- case EVEL_JCS_NV_PAIR_NAMES:
- evel_store_nv_pair_name(item);
- stored = true;
- break;
-
- case EVEL_JCS_FIELD_NAMES:
- evel_store_suppressed_field_name(item);
- stored = true;
- break;
-
- default:
- EVEL_DEBUG("Ignoring item in state: %s",
- evel_jcs_strings[evel_json_command_state]);
- break;
- }
-
- if (!stored)
- {
- EVEL_DEBUG("Ignored item: %s", item);
- free(item);
- }
-
- /***************************************************************************/
- /* We need another item. This is purely defensive. */
- /***************************************************************************/
- entry->json_state = EVEL_JSON_ITEM;
-
- /***************************************************************************/
- /* Count the item. */
- /***************************************************************************/
- entry->json_count++;
-}
-
-/**************************************************************************//**
- * Set the JSON command state to a new value.
- *
- * @param new_state The new state to set.
- *****************************************************************************/
-void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state)
-{
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(evel_json_command_state < EVEL_JCS_MAX);
- assert(new_state < EVEL_JCS_MAX);
-
- /***************************************************************************/
- /* Provide common debug, and set the new state. */
- /***************************************************************************/
- EVEL_DEBUG("Command State: %s -> %s",
- evel_jcs_strings[evel_json_command_state],
- evel_jcs_strings[new_state]);
- evel_json_command_state = new_state;
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Produce debug output from a JSON token.
- *
- * @param chunk Memory chunk containing the JSON buffer.
- * @param token Token to dump.
- *****************************************************************************/
-void evel_debug_token(const MEMORY_CHUNK * const chunk,
- const jsmntok_t * const token)
-{
- char temp_char;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(token->type > 0);
- assert(token->type < JSON_TOKEN_TYPES);
-
- /***************************************************************************/
- /* Log the token, leaving it in the state in which it started. */
- /***************************************************************************/
- temp_char = chunk->memory[token->end];
- chunk->memory[token->end] = '\0';
- EVEL_DEBUG("JSON token type: %s", evel_json_token_strings[token->type]);
- EVEL_DEBUG("JSON token: %s", chunk->memory + token->start);
- chunk->memory[token->end] = temp_char;
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Post a response to the commandList.
- *
- * @param post Memory chunk in which to post a response.
- *****************************************************************************/
-void evel_command_list_response(MEMORY_CHUNK * const post)
-{
- char * json_post;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(post != NULL);
- assert(post->memory == NULL);
-
- if (evel_provide_throttling_state)
- {
- EVEL_DEBUG("Provide throttling state");
-
- /*************************************************************************/
- /* Encode the response, making it printf-able for debug. */
- /*************************************************************************/
- json_post = malloc(EVEL_MAX_JSON_BODY);
- assert(json_post != NULL);
- post->size = evel_json_encode_throttle(json_post, EVEL_MAX_JSON_BODY - 1);
- post->memory = json_post;
- post->memory[post->size] = '\0';
- evel_provide_throttling_state = false;
- }
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Encode the full throttling specification according to AT&T's schema.
- *
- * @param json Pointer to where to store the JSON encoded data.
- * @param max_size Size of storage available in json_body.
- * @returns Number of bytes actually written.
- *****************************************************************************/
-int evel_json_encode_throttle(char * const json, const int max_size)
-{
- bool throttled;
- int domain;
- int offset;
- bool domain_added;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(json != NULL);
- assert(max_size > 0);
-
- /***************************************************************************/
- /* Work out if we're throttled. */
- /***************************************************************************/
- throttled = false;
- for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
- {
- if (evel_throttle_spec[domain] != NULL)
- {
- throttled = true;
- }
- }
-
- /***************************************************************************/
- /* Encode the response. */
- /***************************************************************************/
- offset = 0;
- offset += snprintf(json + offset, max_size - offset,
- "{\"eventThrottlingState\": {");
- offset += snprintf(json + offset, max_size - offset,
- "\"eventThrottlingMode\": \"%s\"",
- throttled ? "throttled" : "normal");
- if (throttled)
- {
- offset += snprintf(json + offset, max_size - offset,
- ", \"eventDomainThrottleSpecificationList\": [");
-
- domain_added = false;
- for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
- {
- if (evel_throttle_spec[domain] != NULL)
- {
- if (domain_added)
- {
- offset += snprintf(json + offset, max_size - offset, ", ");
- }
-
- offset += evel_json_encode_throttle_spec(json + offset,
- max_size - offset,
- domain);
- domain_added = true;
- }
- }
-
- offset += snprintf(json + offset, max_size - offset, "]");
- }
-
- offset += snprintf(json + offset, max_size - offset, "}}");
-
- EVEL_EXIT();
-
- return offset;
-}
-
-/**************************************************************************//**
- * Encode a throttling specification for a domain.
- *
- * @param json Pointer to where to store the JSON encoded data.
- * @param max_size Size of storage available in json_body.
- * @returns Number of bytes actually written.
- *****************************************************************************/
-int evel_json_encode_throttle_spec(char * const json,
- const int max_size,
- const EVEL_EVENT_DOMAINS domain)
-{
- int offset;
- EVEL_THROTTLE_SPEC * throttle_spec;
- DLIST_ITEM * dlist_item;
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(domain >= EVEL_DOMAIN_FAULT);
- assert(domain < EVEL_MAX_DOMAINS);
- assert(evel_throttle_spec[domain] != NULL);
-
- throttle_spec = evel_throttle_spec[domain];
-
- /***************************************************************************/
- /* Encode the domain. */
- /***************************************************************************/
- offset = 0;
- offset += snprintf(json + offset, max_size - offset,
- "{");
- offset += snprintf(json + offset, max_size - offset,
- "\"eventDomain\": \"%s\"",
- evel_domain_strings[domain]);
-
- /***************************************************************************/
- /* Encode "suppressedFieldNames". */
- /***************************************************************************/
- dlist_item = dlist_get_first(&throttle_spec->suppressed_field_names);
- if (dlist_item != NULL)
- {
- offset += snprintf(json + offset, max_size - offset,
- ", \"suppressedFieldNames\": [");
- while (dlist_item != NULL)
- {
- char * suppressed_field = dlist_item->item;
- assert(suppressed_field != NULL);
-
- offset += snprintf(json + offset, max_size - offset,
- "\"%s\"", suppressed_field);
- dlist_item = dlist_get_next(dlist_item);
- if (dlist_item != NULL)
- {
- offset += snprintf(json + offset, max_size - offset, ", ");
- }
- }
-
- offset += snprintf(json + offset, max_size - offset, "]");
- }
-
- /***************************************************************************/
- /* Encode "suppressedNvPairsList". */
- /***************************************************************************/
- dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
- if (dlist_item != NULL)
- {
- offset += snprintf(json + offset, max_size - offset,
- ", \"suppressedNvPairsList\": [");
- while (dlist_item != NULL)
- {
- offset += evel_json_encode_nv_pairs(json + offset,
- max_size - offset,
- dlist_item->item);
- dlist_item = dlist_get_next(dlist_item);
- if (dlist_item != NULL)
- {
- offset += snprintf(json + offset, max_size - offset, ", ");
- }
- }
-
- offset += snprintf(json + offset, max_size - offset, "]");
- }
-
- offset += snprintf(json + offset, max_size - offset, "}");
-
- EVEL_EXIT();
-
- return offset;
-}
-
-/**************************************************************************//**
- * Encode a single "suppressedNvPairsListEntry".
- *
- * @param json Pointer to where to store the JSON encoded data.
- * @param max_size Size of storage available in json_body.
- * @returns Number of bytes actually written.
- *****************************************************************************/
-int evel_json_encode_nv_pairs(char * const json,
- const int max_size,
- EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
-{
- DLIST_ITEM * dlist_item;
- char * name;
- int offset;
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(nv_pairs != NULL);
- assert(nv_pairs->nv_pair_field_name != NULL);
- assert(!dlist_is_empty(&nv_pairs->suppressed_nv_pair_names));
-
- /***************************************************************************/
- /* Encode it. */
- /***************************************************************************/
- offset = 0;
- offset += snprintf(json + offset, max_size - offset, "{");
- offset += snprintf(json + offset, max_size - offset,
- "\"nvPairFieldName\": \"%s\"",
- nv_pairs->nv_pair_field_name);
- dlist_item = dlist_get_first(&nv_pairs->suppressed_nv_pair_names);
- offset += snprintf(json + offset, max_size - offset,
- ", \"suppressedNvPairNames\": [");
- while (dlist_item != NULL)
- {
- name = dlist_item->item;
- assert(name != NULL);
- offset += snprintf(json + offset, max_size - offset, "\"%s\"", name);
- dlist_item = dlist_get_next(dlist_item);
- if (dlist_item != NULL)
- {
- offset += snprintf(json + offset, max_size - offset, ", ");
- }
- }
- offset += snprintf(json + offset, max_size - offset, "]");
- offset += snprintf(json + offset, max_size - offset, "}");
-
- EVEL_EXIT();
-
- return offset;
-}
-
-/**************************************************************************//**
- * Method called when we open a "command" object.
- *****************************************************************************/
-void evel_open_command()
-{
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Make some assertions. */
- /***************************************************************************/
- assert(evel_command_type_value == NULL);
- assert(evel_measurement_interval_value == NULL);
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Method called when we close a "command" object.
- *****************************************************************************/
-void evel_close_command()
-{
- EVEL_ENTER();
-
- /***************************************************************************/
- /* If a commandType was provided, fan out and handle it now what we have */
- /* fathered all related information. */
- /* */
- /* Note that we handle throttling specification and measurement interval */
- /* updates immediately on closing the command (not the list). We could */
- /* reject *all* commands in a list if any of them are invalid, but we are */
- /* take a best-effort strategy here - any valid-looking command gets */
- /* implemented regardless of what follows. */
- /***************************************************************************/
- if (evel_command_type_value != NULL)
- {
- EVEL_DEBUG("Closing command %s", evel_command_type_value);
-
- if (strcmp(evel_command_type_value, "provideThrottlingState") == 0)
- {
- evel_provide_throttling_state = true;
- }
- else if (strcmp(evel_command_type_value, "throttlingSpecification") == 0)
- {
- evel_set_throttling_spec();
- }
- else if (strcmp(evel_command_type_value, "measurementIntervalChange") == 0)
- {
- evel_set_measurement_interval();
- }
- else
- {
- EVEL_ERROR("Ignoring unknown commandType: %s\n",
- evel_command_type_value);
- }
-
- /*************************************************************************/
- /* Free the captured "commandType" value. */
- /*************************************************************************/
- free(evel_command_type_value);
- evel_command_type_value = NULL;
- }
-
- /***************************************************************************/
- /* There could be an unused working throttle spec at this point - if the */
- /* "throttlingSpecification" commandType was not provided, or an invalid */
- /* domain was provided, or was not provided at all. */
- /***************************************************************************/
- if (evel_temp_throttle != NULL)
- {
- evel_throttle_free(evel_temp_throttle);
- evel_temp_throttle = NULL;
- }
-
- /***************************************************************************/
- /* Similarly, the domain could be set. */
- /***************************************************************************/
- evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
-
- /***************************************************************************/
- /* There could be an unused measurement interval value at this point - if */
- /* the "measurementIntervalChange" command was not provided. */
- /***************************************************************************/
- if (evel_measurement_interval_value != NULL)
- {
- free(evel_measurement_interval_value);
- evel_measurement_interval_value = NULL;
- }
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Set the provided throttling specification, when the command closes.
- *****************************************************************************/
-void evel_set_throttling_spec()
-{
- EVEL_ENTER();
-
- if ((evel_throttle_spec_domain >= 0) &&
- (evel_throttle_spec_domain < EVEL_MAX_DOMAINS))
- {
- EVEL_DEBUG("Updating throttle spec for domain: %s",
- evel_domain_strings[evel_throttle_spec_domain]);
-
- /*************************************************************************/
- /* Free off the previous throttle specification for the domain, if there */
- /* is one. */
- /*************************************************************************/
- if (evel_throttle_spec[evel_throttle_spec_domain] != NULL)
- {
- evel_throttle_free(evel_throttle_spec[evel_throttle_spec_domain]);
- }
-
- /*************************************************************************/
- /* Finalize the working throttling spec, if there is one. */
- /*************************************************************************/
- if (evel_temp_throttle != NULL)
- {
- evel_throttle_finalize(evel_temp_throttle);
- }
-
- /*************************************************************************/
- /* Replace the throttle specification for the domain with the working */
- /* throttle specification. This could be NULL, if an empty throttle */
- /* specification has been received for a domain. */
- /*************************************************************************/
- evel_throttle_spec[evel_throttle_spec_domain] = evel_temp_throttle;
- evel_temp_throttle = NULL;
- }
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Set the provided measurement interval, when the command closes.
- *****************************************************************************/
-void evel_set_measurement_interval()
-{
- EVEL_ENTER();
-
- if (evel_measurement_interval_value != NULL)
- {
- const long int value = strtol(evel_measurement_interval_value, NULL, 10);
-
- if ((value >= 0) && (value <= INT_MAX))
- {
- /***********************************************************************/
- /* Lock, update, unlock. */
- /***********************************************************************/
- EVEL_DEBUG("Updating measurement interval to %d\n", value);
-
- pthread_mutex_lock(&evel_measurement_interval_mutex);
- evel_measurement_interval = value;
- pthread_mutex_unlock(&evel_measurement_interval_mutex);
- }
- else
- {
- EVEL_ERROR("Ignoring invalid measurement interval: %s",
- evel_measurement_interval_value);
- }
- }
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Method called when we open an "eventDomainThrottleSpecification" object.
- *****************************************************************************/
-void evel_open_throttle_spec()
-{
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(evel_throttle_spec_domain_value == NULL);
- assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
- assert(evel_temp_throttle == NULL);
-
- /***************************************************************************/
- /* Allocate and initialize an ::EVEL_THROTTLE_SPEC in which to hold */
- /* captured JSON elements. */
- /***************************************************************************/
- evel_temp_throttle = malloc(sizeof(EVEL_THROTTLE_SPEC));
- assert(evel_temp_throttle != NULL);
- dlist_initialize(&evel_temp_throttle->suppressed_field_names);
- dlist_initialize(&evel_temp_throttle->suppressed_nv_pairs_list);
- evel_temp_throttle->hash_field_names = NULL;
- evel_temp_throttle->hash_nv_pairs_list = NULL;
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Method called when we close an "eventDomainThrottleSpecification" object.
- *****************************************************************************/
-void evel_close_throttle_spec()
-{
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Decode, free and blank a captured event domain value. */
- /***************************************************************************/
- if (evel_throttle_spec_domain_value != NULL)
- {
- evel_throttle_spec_domain =
- evel_decode_domain(evel_throttle_spec_domain_value);
- free(evel_throttle_spec_domain_value);
- evel_throttle_spec_domain_value = NULL;
- }
-
- /***************************************************************************/
- /* Free off an empty working throttle spec, to stop it being used. This */
- /* state should be represented by a NULL pointer for the domain. */
- /***************************************************************************/
- if (evel_temp_throttle != NULL)
- {
- if (dlist_is_empty(&evel_temp_throttle->suppressed_field_names) &&
- dlist_is_empty(&evel_temp_throttle->suppressed_nv_pairs_list))
- {
- free(evel_temp_throttle);
- evel_temp_throttle = NULL;
- }
- }
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Convert a value for an "eventDomain" into an ::EVEL_EVENT_DOMAINS.
- *
- * @param domain_value The domain string value to decode.
- * @returns The matching ::EVEL_EVENT_DOMAINS, or ::EVEL_MAX_DOMAINS on error.
- *****************************************************************************/
-EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value)
-{
- EVEL_EVENT_DOMAINS result;
- int ii;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(domain_value != NULL);
-
- result = EVEL_MAX_DOMAINS;
- for (ii = EVEL_DOMAIN_FAULT; ii < EVEL_MAX_DOMAINS; ii++)
- {
- assert(evel_domain_strings[ii] != NULL);
- if (strcmp(evel_domain_strings[ii], domain_value) == 0)
- {
- result = ii;
- }
- }
-
- EVEL_EXIT();
-
- return result;
-}
-
-/**************************************************************************//**
- * Method called when we open a "suppressedNvPairsListEntry" object.
- *****************************************************************************/
-void evel_open_nv_pairs_list_entry()
-{
- EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(evel_temp_throttle != NULL);
-
- /***************************************************************************/
- /* Allocate and initialize an ::EVEL_SUPPRESSED_NV_PAIRS, and add it to */
- /* the list. */
- /***************************************************************************/
- nv_pairs = malloc(sizeof(EVEL_SUPPRESSED_NV_PAIRS));
- assert(nv_pairs != NULL);
- nv_pairs->nv_pair_field_name = NULL;
- dlist_initialize(&nv_pairs->suppressed_nv_pair_names);
- nv_pairs->hash_nv_pair_names = NULL;
- dlist_push_last(&evel_temp_throttle->suppressed_nv_pairs_list, nv_pairs);
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Method called when we close a "suppressedNvPairsListEntry" object.
- *****************************************************************************/
-void evel_close_nv_pairs_list_entry()
-{
- EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
- EVEL_SUPPRESSED_NV_PAIRS * popped;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Get the latest nv pairs. This also performs the required checks. */
- /***************************************************************************/
- nv_pairs = evel_get_last_nv_pairs();
-
- /***************************************************************************/
- /* For a "suppressedNvPairsListEntry" to have any meaning, we need both */
- /* "nvPairFieldName" and "suppressedNvPairNames". If we don't, then pop */
- /* and free whatever we just collected. */
- /***************************************************************************/
- if ((nv_pairs->nv_pair_field_name == NULL) ||
- dlist_is_empty(&nv_pairs->suppressed_nv_pair_names))
- {
- popped = dlist_pop_last(&evel_temp_throttle->suppressed_nv_pairs_list);
- assert(popped == nv_pairs);
- evel_throttle_free_nv_pair(popped);
- }
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Store an "nvPairFieldName" value in the working throttle spec.
- *
- * @param value The value to store.
- *****************************************************************************/
-void evel_store_nv_pair_field_name(char * const value)
-{
- EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Get the latest nv pairs. This also performs the required checks. */
- /***************************************************************************/
- nv_pairs = evel_get_last_nv_pairs();
-
- /***************************************************************************/
- /* Store the value. */
- /***************************************************************************/
- nv_pairs->nv_pair_field_name = value;
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Store a "suppressedNvPairNames" item in the working throttle spec.
- *
- * @param item The item to store.
- *****************************************************************************/
-void evel_store_nv_pair_name(char * const item)
-{
- EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Get the latest nv pairs. This also performs the required checks. */
- /***************************************************************************/
- nv_pairs = evel_get_last_nv_pairs();
-
- /***************************************************************************/
- /* Store the item. */
- /***************************************************************************/
- dlist_push_last(&nv_pairs->suppressed_nv_pair_names, item);
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Store a "suppressedFieldNames" item in the working throttle spec.
- *
- * @param item The item to store.
- *****************************************************************************/
-void evel_store_suppressed_field_name(char * const item)
-{
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(evel_temp_throttle != NULL);
-
- /***************************************************************************/
- /* Store the item. */
- /***************************************************************************/
- dlist_push_last(&evel_temp_throttle->suppressed_field_names, item);
-
- EVEL_EXIT();
-}
-
-/**************************************************************************//**
- * Get the last added suppressed nv pairs list entry in the working spec.
- *
- * @returns The last entry.
- *****************************************************************************/
-EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs()
-{
- DLIST_ITEM * dlist_item;
- EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check preconditions. */
- /***************************************************************************/
- assert(evel_temp_throttle != NULL);
-
- /***************************************************************************/
- /* Get the pair that was added when we opened the list entry. */
- /***************************************************************************/
- dlist_item = dlist_get_last(&evel_temp_throttle->suppressed_nv_pairs_list);
- assert(dlist_item != NULL);
- nv_pairs = dlist_item->item;
- assert(nv_pairs != NULL);
-
- EVEL_EXIT();
-
- return nv_pairs;
-}