diff options
author | Marco Platania <platania@research.att.com> | 2017-05-18 11:09:08 -0400 |
---|---|---|
committer | Marco Platania <platania@research.att.com> | 2017-05-18 11:09:08 -0400 |
commit | fee6de844f9d4c3aad87733734d35df50117b6b0 (patch) | |
tree | 3f42567107ac4a10795c8e80c42b479c4502cbda /VES5.0/evel/evel-library/code/evel_library/evel_throttle.c | |
parent | f3fe765461685a753c0f5b061c5c47383c75829f (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.c | 2116 |
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; -} |