1 /**************************************************************************//**
5 * Simple event manager that is responsible for taking events (Heartbeats,
6 * Faults and Measurements) from the ring-buffer and posting them to the API.
11 * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
16 * 1. Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement: This product includes
23 * software developed by the AT&T.
24 * 4. Neither the name of AT&T nor the names of its contributors may be used to
25 * endorse or promote products derived from this software without specific
26 * prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
29 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31 * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 *****************************************************************************/
48 #include "evel_throttle.h"
50 /*****************************************************************************/
51 /* The Event Throttling State for all domains, indexed by */
52 /* ::EVEL_EVENT_DOMAINS, corresponding to JSON eventDomain. */
54 /* A given domain is in a throttled state if ::evel_throttle_spec is */
56 /*****************************************************************************/
57 static EVEL_THROTTLE_SPEC * evel_throttle_spec[EVEL_MAX_DOMAINS];
59 /*****************************************************************************/
60 /* The current measurement interval. Default: MEASUREMENT_INTERVAL_UKNOWN. */
61 /* Must be protected by evel_measurement_interval_mutex. */
62 /*****************************************************************************/
63 static int evel_measurement_interval;
65 /*****************************************************************************/
66 /* Mutex protecting evel_measurement_interval from contention between an */
67 /* EVEL client reading it, and the EVEL event handler updating it. */
68 /*****************************************************************************/
69 static pthread_mutex_t evel_measurement_interval_mutex;
71 /*****************************************************************************/
72 /* Flag stating that we have received a "provideThrottlingState" command. */
73 /* Set during JSON processing and cleared on sending the throttling state. */
74 /*****************************************************************************/
75 static bool evel_provide_throttling_state;
77 /*****************************************************************************/
78 /* Holder for the "commandType" value during JSON processing. */
79 /*****************************************************************************/
80 static char * evel_command_type_value;
82 /*****************************************************************************/
83 /* Holder for the "measurementInterval" value during JSON processing. */
84 /*****************************************************************************/
85 static char * evel_measurement_interval_value;
87 /*****************************************************************************/
88 /* Holder for the "eventDomain" value during JSON processing. */
89 /*****************************************************************************/
90 static char * evel_throttle_spec_domain_value;
92 /*****************************************************************************/
93 /* Decoded version of ::evel_throttle_spec_domain_value. */
94 /*****************************************************************************/
95 static EVEL_EVENT_DOMAINS evel_throttle_spec_domain;
97 /*****************************************************************************/
98 /* During JSON processing of a single throttling specification, we collect */
99 /* parameters in this working ::EVEL_THROTTLE_SPEC */
100 /*****************************************************************************/
101 static EVEL_THROTTLE_SPEC * evel_temp_throttle;
103 /*****************************************************************************/
104 /* State tracking our progress through the command list */
105 /*****************************************************************************/
106 EVEL_JSON_COMMAND_STATE evel_json_command_state;
108 /*****************************************************************************/
109 /* Debug strings for ::EVEL_JSON_COMMAND_STATE. */
110 /*****************************************************************************/
111 static const char * const evel_jcs_strings[EVEL_JCS_MAX] = {
113 "EVEL_JCS_COMMAND_LIST",
114 "EVEL_JCS_COMMAND_LIST_ENTRY",
117 "EVEL_JCS_FIELD_NAMES",
118 "EVEL_JCS_PAIRS_LIST",
119 "EVEL_JCS_PAIRS_LIST_ENTRY",
120 "EVEL_JCS_NV_PAIR_NAMES"
123 /*****************************************************************************/
124 /* Debug strings for JSON token type. */
125 /*****************************************************************************/
126 #define JSON_TOKEN_TYPES (JSMN_PRIMITIVE + 1)
127 static const char * const evel_json_token_strings[JSON_TOKEN_TYPES] = {
135 /*****************************************************************************/
136 /* Debug strings for JSON domains. */
137 /*****************************************************************************/
138 static const char * evel_domain_strings[EVEL_MAX_DOMAINS] = {
142 "measurementsForVfScaling",
152 /*****************************************************************************/
153 /* Local prototypes. */
154 /*****************************************************************************/
155 static void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec);
156 static struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys);
157 static void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec);
158 static void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
159 static void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
160 const MEMORY_CHUNK * const chunk);
161 static bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
162 const int num_required,
163 const EVEL_JSON_STATE new_state);
164 static void evel_stack_pop(EVEL_JSON_STACK * const json_stack);
165 static void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack);
166 static char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
167 const jsmntok_t * const token);
168 static void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
169 const jsmntok_t * const token);
170 static void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
171 const jsmntok_t * const token);
172 static void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
173 const jsmntok_t * const token);
174 static void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state);
175 static void evel_debug_token(const MEMORY_CHUNK * const chunk,
176 const jsmntok_t * const token);
177 static void evel_command_list_response(MEMORY_CHUNK * const post);
178 static int evel_json_encode_throttle(char * const json, const int max_size);
179 static int evel_json_encode_throttle_spec(char * const json,
181 const EVEL_EVENT_DOMAINS domain);
182 static int evel_json_encode_nv_pairs(char * const json,
184 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
185 static void evel_close_command();
186 static void evel_open_command();
187 static void evel_set_throttling_spec();
188 static void evel_set_measurement_interval();
189 static void evel_open_throttle_spec();
190 static void evel_close_throttle_spec();
191 static EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value);
192 static void evel_open_nv_pairs_list_entry();
193 static void evel_close_nv_pairs_list_entry();
194 static void evel_store_nv_pair_field_name(char * const value);
195 static void evel_store_nv_pair_name(char * const item);
196 static void evel_store_suppressed_field_name(char * const item);
197 static EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs();
199 /**************************************************************************//**
200 * Return the current measurement interval provided by the Event Listener.
202 * @returns The current measurement interval
203 * @retval EVEL_MEASUREMENT_INTERVAL_UKNOWN (0) - interval has not been
205 *****************************************************************************/
206 int evel_get_measurement_interval()
212 /***************************************************************************/
213 /* Lock, read, unlock. */
214 /***************************************************************************/
215 pthread_mutex_lock(&evel_measurement_interval_mutex);
216 result = evel_measurement_interval;
217 pthread_mutex_unlock(&evel_measurement_interval_mutex);
224 /**************************************************************************//**
225 * Return the ::EVEL_THROTTLE_SPEC for a given domain.
227 * @param domain The domain for which to return state.
228 *****************************************************************************/
229 EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain)
231 EVEL_THROTTLE_SPEC * result;
235 /***************************************************************************/
236 /* Check preconditions. */
237 /***************************************************************************/
238 assert(domain < EVEL_MAX_DOMAINS);
240 result = evel_throttle_spec[domain];
247 /**************************************************************************//**
248 * Determine whether a field_name should be suppressed.
250 * @param throttle_spec Throttle specification for the domain being encoded.
251 * @param field_name The field name to encoded or suppress.
252 * @return true if the field_name should be suppressed, false otherwise.
253 *****************************************************************************/
254 bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC * throttle_spec,
255 const char * const field_name)
257 bool suppress = false;
261 /***************************************************************************/
262 /* Check preconditions. */
263 /***************************************************************************/
264 assert(field_name != NULL);
266 /***************************************************************************/
267 /* If the throttle spec and hash table exist, query the field_names table. */
268 /***************************************************************************/
269 if ((throttle_spec != NULL) && (throttle_spec->hash_field_names != NULL))
273 hash_query.key = (char * const) field_name;
274 suppress = (hsearch_r(hash_query,
277 throttle_spec->hash_field_names) != 0);
285 /**************************************************************************//**
286 * Determine whether a name-value pair should be allowed (not suppressed).
288 * @param throttle_spec Throttle specification for the domain being encoded.
289 * @param field_name The field name holding the name-value pairs.
290 * @param name The name of the name-value pair to encoded or suppress.
291 * @return true if the name-value pair should be suppressed, false otherwise.
292 *****************************************************************************/
293 bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC * throttle_spec,
294 const char * const field_name,
295 const char * const name)
297 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
299 bool suppress = false;
303 /***************************************************************************/
304 /* Check preconditions. */
305 /***************************************************************************/
306 assert(field_name != NULL);
307 assert(name != NULL);
309 /***************************************************************************/
310 /* If the throttle spec and hash table exist, query the nv_pairs table. */
311 /***************************************************************************/
312 if ((throttle_spec != NULL) && (throttle_spec->hash_nv_pairs_list != NULL))
316 hash_query.key = (char * const) field_name;
317 hit = (hsearch_r(hash_query,
320 throttle_spec->hash_nv_pairs_list) != 0);
323 nv_pairs = hash_result->data;
327 /***************************************************************************/
328 /* If we got a hit, and the nv_pairs and hash table exist, query the */
329 /* nv_pairs table. */
330 /***************************************************************************/
331 if (hit && (nv_pairs != NULL) && (nv_pairs->hash_nv_pair_names != NULL))
335 hash_query.key = (char * const) name;
336 suppress = (hsearch_r(hash_query,
339 nv_pairs->hash_nv_pair_names) != 0);
347 /**************************************************************************//**
348 * Initialize event throttling to the default state.
350 * Called from ::evel_initialize.
351 *****************************************************************************/
352 void evel_throttle_initialize()
359 for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
361 evel_throttle_spec[ii] = NULL;
364 pthread_rc = pthread_mutex_init(&evel_measurement_interval_mutex, NULL);
365 assert(pthread_rc == 0);
367 evel_measurement_interval = EVEL_MEASUREMENT_INTERVAL_UKNOWN;
372 /**************************************************************************//**
373 * Clean up event throttling.
375 * Called from ::evel_terminate.
376 *****************************************************************************/
377 void evel_throttle_terminate()
384 for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
386 if (evel_throttle_spec[ii] != NULL)
388 evel_throttle_free(evel_throttle_spec[ii]);
389 evel_throttle_spec[ii] = NULL;
393 pthread_rc = pthread_mutex_destroy(&evel_measurement_interval_mutex);
394 assert(pthread_rc == 0);
399 /**************************************************************************//**
400 * Finalize a single ::EVEL_THROTTLE_SPEC.
402 * Now that the specification is collected, build hash tables to simplify the
405 * @param throttle_spec The ::EVEL_THROTTLE_SPEC to finalize.
406 *****************************************************************************/
407 void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec)
410 DLIST_ITEM * dlist_item;
415 /***************************************************************************/
416 /* Check preconditions. */
417 /***************************************************************************/
418 assert(throttle_spec != NULL);
420 /***************************************************************************/
421 /* Populate the hash table for suppressed field names. */
422 /***************************************************************************/
423 throttle_spec->hash_field_names =
424 evel_throttle_hash_create(&throttle_spec->suppressed_field_names);
426 /***************************************************************************/
427 /* Create the hash table for suppressed nv pairs. */
428 /***************************************************************************/
429 nv_pairs_count = dlist_count(&throttle_spec->suppressed_nv_pairs_list);
430 if (nv_pairs_count > 0)
432 throttle_spec->hash_nv_pairs_list = calloc(1, sizeof(struct hsearch_data));
433 assert(throttle_spec->hash_nv_pairs_list != NULL);
435 /*************************************************************************/
436 /* Provide plenty of space in the table - see hcreate_r notes. */
437 /*************************************************************************/
438 if (hcreate_r(nv_pairs_count * 2, throttle_spec->hash_nv_pairs_list) == 0)
440 EVEL_ERROR("Failed to create hash table");
441 free(throttle_spec->hash_nv_pairs_list);
442 throttle_spec->hash_nv_pairs_list = NULL;
446 /***************************************************************************/
447 /* Populate the hash tables under suppressed field names. */
448 /***************************************************************************/
449 dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
450 while (dlist_item != NULL)
452 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs = dlist_item->item;
455 /*************************************************************************/
456 /* Set the key to the string, and the item to the nv_pairs. */
457 /*************************************************************************/
458 assert(nv_pairs != NULL);
459 hash_add.key = nv_pairs->nv_pair_field_name;
460 hash_add.data = nv_pairs;
461 hsearch_r(hash_add, ENTER, &add_result, throttle_spec->hash_nv_pairs_list);
463 /*************************************************************************/
464 /* Create the nv_pair_names hash since we're in here. */
465 /*************************************************************************/
466 nv_pairs->hash_nv_pair_names =
467 evel_throttle_hash_create(&nv_pairs->suppressed_nv_pair_names);
469 dlist_item = dlist_get_next(dlist_item);
475 /**************************************************************************//**
476 * Create and populate a hash table from a DLIST of keys.
478 * @param hash_keys Pointer to a DLIST of hash table keys.
479 * @return Pointer to the created hash-table, or NULL on failure.
480 *****************************************************************************/
481 struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys)
484 struct hsearch_data * hash_table;
489 /***************************************************************************/
490 /* Check preconditions. */
491 /***************************************************************************/
492 assert(hash_keys != NULL);
494 /***************************************************************************/
495 /* Count the keys and if there are any, populate the hash table with them. */
496 /***************************************************************************/
497 key_count = dlist_count(hash_keys);
500 EVEL_DEBUG("Populating table for %d keys", key_count);
502 hash_table = calloc(1, sizeof(struct hsearch_data));
503 assert(hash_table != NULL);
505 /*************************************************************************/
506 /* We need to leave plenty of space in the table - see hcreate_r notes. */
507 /*************************************************************************/
508 if (hcreate_r(key_count * 2, hash_table) != 0)
510 DLIST_ITEM * dlist_item;
511 dlist_item = dlist_get_first(hash_keys);
512 while (dlist_item != NULL)
514 assert(dlist_item->item != NULL);
516 /*********************************************************************/
517 /* Set the key and data to the item, which is a string in this case. */
518 /*********************************************************************/
520 hash_add.key = dlist_item->item;
521 hash_add.data = dlist_item->item;
522 hsearch_r(hash_add, ENTER, &add_result, hash_table);
523 dlist_item = dlist_get_next(dlist_item);
528 EVEL_ERROR("Failed to create hash table");
543 /**************************************************************************//**
544 * Free resources associated with a single ::EVEL_THROTTLE_SPEC.
546 * @param throttle_spec The ::EVEL_THROTTLE_SPEC to free.
547 *****************************************************************************/
548 void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec)
551 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
555 /***************************************************************************/
556 /* Check preconditions. */
557 /***************************************************************************/
558 assert(throttle_spec != NULL);
560 /***************************************************************************/
561 /* Free any hash tables. */
562 /***************************************************************************/
563 if (throttle_spec->hash_field_names != NULL)
565 hdestroy_r(throttle_spec->hash_field_names);
566 free(throttle_spec->hash_field_names);
568 if (throttle_spec->hash_nv_pairs_list != NULL)
570 hdestroy_r(throttle_spec->hash_nv_pairs_list);
571 free(throttle_spec->hash_nv_pairs_list);
574 /***************************************************************************/
575 /* Iterate through the linked lists, freeing memory. */
576 /***************************************************************************/
577 field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
578 while (field_name != NULL)
581 field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
584 nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
585 while (nv_pairs != NULL)
587 evel_throttle_free_nv_pair(nv_pairs);
588 nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
596 /**************************************************************************//**
597 * Free resources associated with a single ::EVEL_SUPPRESSED_NV_PAIR.
599 * @param nv_pair The ::EVEL_SUPPRESSED_NV_PAIR to free.
600 *****************************************************************************/
601 void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
603 char * suppressed_name;
607 /***************************************************************************/
608 /* Check preconditions. */
609 /***************************************************************************/
610 assert(nv_pairs != NULL);
612 /***************************************************************************/
613 /* Free any hash tables. */
614 /***************************************************************************/
615 if (nv_pairs->hash_nv_pair_names != NULL)
617 hdestroy_r(nv_pairs->hash_nv_pair_names);
618 free(nv_pairs->hash_nv_pair_names);
621 /***************************************************************************/
622 /* Iterate through the linked lists, freeing memory. */
623 /***************************************************************************/
624 suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
625 while (suppressed_name != NULL)
627 free(suppressed_name);
628 suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
630 if (nv_pairs->nv_pair_field_name != NULL)
632 free(nv_pairs->nv_pair_field_name);
639 /**************************************************************************//**
640 * Handle a JSON response from the listener, as a list of tokens from JSMN.
642 * @param chunk Memory chunk containing the JSON buffer.
643 * @param json_tokens Array of tokens to handle.
644 * @param num_tokens The number of tokens to handle.
645 * @param post The memory chunk in which to place any resulting POST.
646 * @return true if the command was handled, false otherwise.
647 *****************************************************************************/
648 bool evel_handle_command_list(const MEMORY_CHUNK * const chunk,
649 const jsmntok_t * const json_tokens,
650 const int num_tokens,
651 MEMORY_CHUNK * const post)
653 EVEL_JSON_STACK stack;
654 EVEL_JSON_STACK * json_stack = &stack;
655 EVEL_JSON_STACK_ENTRY * entry;
662 /***************************************************************************/
663 /* Check preconditions. */
664 /***************************************************************************/
665 assert(chunk != NULL);
666 assert(json_tokens != NULL);
667 assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS);
669 /***************************************************************************/
670 /* Collect one top-level item. */
671 /***************************************************************************/
672 evel_init_json_stack(json_stack, chunk);
674 /***************************************************************************/
675 /* Initialize JSON processing variables. */
676 /***************************************************************************/
677 evel_provide_throttling_state = false;
678 evel_command_type_value = NULL;
679 evel_measurement_interval_value = NULL;
680 evel_throttle_spec_domain_value = NULL;
681 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
682 evel_temp_throttle = NULL;
683 evel_json_command_state = EVEL_JCS_START;
685 /***************************************************************************/
686 /* Loop through the tokens, keeping a stack of state representing the */
687 /* nested JSON structure (see json_state). We also track our way through */
688 /* the ::EVEL_JSON_COMMAND_STATE as we go. */
689 /***************************************************************************/
690 while (json_ok && (token_index < num_tokens))
692 const jsmntok_t * const token = &json_tokens[token_index];
696 evel_debug_token(chunk, token);
699 /*************************************************************************/
700 /* We may have popped or pushed, so always re-evaluate the stack entry. */
701 /*************************************************************************/
702 entry = &json_stack->entry[json_stack->level];
707 if ((entry->json_state == EVEL_JSON_ITEM) ||
708 (entry->json_state == EVEL_JSON_VALUE))
710 json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_KEY);
714 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
715 entry->json_state, token_index, token->type);
721 if ((entry->json_state == EVEL_JSON_ITEM) ||
722 (entry->json_state == EVEL_JSON_VALUE))
724 json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_ITEM);
728 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
729 entry->json_state, token_index, token->type);
735 if (entry->json_state == EVEL_JSON_KEY)
737 evel_stack_store_key(json_stack, token);
739 else if (entry->json_state == EVEL_JSON_VALUE)
741 evel_stack_store_value(json_stack, token);
743 else if (entry->json_state == EVEL_JSON_ITEM)
745 evel_stack_store_item(json_stack, token);
749 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
750 entry->json_state, token_index, token->type);
756 if (entry->json_state == EVEL_JSON_VALUE)
758 evel_stack_store_value(json_stack, token);
760 else if (entry->json_state == EVEL_JSON_ITEM)
762 evel_stack_store_item(json_stack, token);
766 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
767 entry->json_state, token_index, token->type);
774 EVEL_ERROR("Unexpected JSON format at token %d (%d)",
775 token_index, token->type);
780 /*************************************************************************/
781 /* Pop the stack if we're counted enough nested items. */
782 /*************************************************************************/
783 evel_stack_pop(json_stack);
788 /***************************************************************************/
789 /* Cleanup the stack - we may have exited without winding it back, if the */
790 /* input was not well formed. */
791 /***************************************************************************/
792 evel_stack_cleanup(json_stack);
794 /***************************************************************************/
795 /* We may want to generate and POST a response to the command list. */
796 /***************************************************************************/
799 evel_command_list_response(post);
802 /***************************************************************************/
803 /* Make sure we're clean on exit. */
804 /***************************************************************************/
805 assert(evel_command_type_value == NULL);
806 assert(evel_measurement_interval_value == NULL);
807 assert(evel_throttle_spec_domain_value == NULL);
808 assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
809 assert(evel_temp_throttle == NULL);
816 /**************************************************************************//**
817 * Copy a copy of an element, in string form.
819 * The caller must manage memory allocated for the copied string.
821 * @param chunk Memory chunk containing the JSON buffer.
822 * @param token The token to copy from.
823 * @return the copy of the element.
824 *****************************************************************************/
825 char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
826 const jsmntok_t * const token)
833 /***************************************************************************/
834 /* Call strdup to copy the string, inserting a temporary \0 for the call. */
835 /***************************************************************************/
836 temp_char = chunk->memory[token->end];
837 chunk->memory[token->end] = '\0';
838 result = strdup(chunk->memory + token->start);
839 assert(result != NULL);
840 chunk->memory[token->end] = temp_char;
847 /**************************************************************************//**
848 * Copy a copy of an element, in string form.
850 * @param json_stack The JSON stack to initialize.
851 * @param chunk The underlying memory chunk used for parsing.
852 *****************************************************************************/
853 void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
854 const MEMORY_CHUNK * const chunk)
856 EVEL_JSON_STACK_ENTRY * entry;
860 json_stack->level = 0;
861 entry = json_stack->entry;
862 entry->json_state = EVEL_JSON_ITEM;
863 entry->json_count = 0;
864 entry->num_required = 1;
865 entry->json_key = NULL;
866 json_stack->chunk = chunk;
871 /**************************************************************************//**
872 * Push a new entry on the stack
874 * @param json_stack The stack.
875 * @param num_required The number of elements required.
876 * @param new_state The state for the new entry.
877 * @return false if we cannot push onto the stack.
878 *****************************************************************************/
879 bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
880 const int num_required,
881 const EVEL_JSON_STATE new_state)
883 EVEL_JSON_STACK_ENTRY * entry;
889 /***************************************************************************/
890 /* Check preconditions. */
891 /***************************************************************************/
892 assert(json_stack != NULL);
893 assert(json_stack->level >= 0);
894 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
895 assert((new_state == EVEL_JSON_ITEM) || (new_state == EVEL_JSON_KEY));
897 /***************************************************************************/
898 /* Check nesting depth, and stop processing if we hit the limit. */
899 /***************************************************************************/
900 if ((json_stack->level + 1) >= EVEL_JSON_STACK_DEPTH)
902 EVEL_ERROR("JSON Nesting is too deep - stop processing");
907 /***************************************************************************/
908 /* Evaluate cases where we recurse and are interested in the contents. */
909 /***************************************************************************/
910 entry = &json_stack->entry[json_stack->level];
911 key = entry->json_key;
913 /***************************************************************************/
914 /* Note that this is the key before we drop a level. */
915 /***************************************************************************/
918 EVEL_DEBUG("Push with key: %s", key);
920 switch (evel_json_command_state)
923 if (strcmp(key, "commandList") == 0)
925 evel_set_command_state(EVEL_JCS_COMMAND_LIST);
929 case EVEL_JCS_COMMAND_LIST_ENTRY:
930 if (strcmp(key, "command") == 0)
933 evel_set_command_state(EVEL_JCS_COMMAND);
937 case EVEL_JCS_COMMAND:
938 if (strcmp(key, "eventDomainThrottleSpecification") == 0)
940 evel_open_throttle_spec();
941 evel_set_command_state(EVEL_JCS_SPEC);
946 if (strcmp(key, "suppressedFieldNames") == 0)
948 evel_set_command_state(EVEL_JCS_FIELD_NAMES);
950 else if (strcmp(key, "suppressedNvPairsList") == 0)
952 evel_set_command_state(EVEL_JCS_PAIRS_LIST);
956 case EVEL_JCS_PAIRS_LIST_ENTRY:
957 if (strcmp(key, "suppressedNvPairNames") == 0)
959 evel_set_command_state(EVEL_JCS_NV_PAIR_NAMES);
963 case EVEL_JCS_FIELD_NAMES:
964 case EVEL_JCS_PAIRS_LIST:
965 case EVEL_JCS_NV_PAIR_NAMES:
967 EVEL_ERROR("Unexpected JSON key %s in state %d",
969 evel_json_command_state);
975 EVEL_DEBUG("Push with no key");
977 /*************************************************************************/
978 /* If we're pushing without a key, then we're in an array. We switch */
979 /* state based on the existing state and stack level. */
980 /*************************************************************************/
981 const int COMMAND_LIST_LEVEL = 2;
982 const int NV_PAIRS_LIST_LEVEL = 6;
984 if ((evel_json_command_state == EVEL_JCS_PAIRS_LIST) &&
985 (json_stack->level == NV_PAIRS_LIST_LEVEL))
987 /***********************************************************************/
988 /* We are entering an object within the "suppressedNvPairsList" array. */
989 /***********************************************************************/
990 evel_open_nv_pairs_list_entry();
991 evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
994 if ((evel_json_command_state == EVEL_JCS_COMMAND_LIST) &&
995 (json_stack->level == COMMAND_LIST_LEVEL))
997 /***********************************************************************/
998 /* We are entering an object within the "commandList" array. */
999 /***********************************************************************/
1000 evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
1004 /***************************************************************************/
1005 /* Push the stack and initialize the entry. */
1006 /***************************************************************************/
1007 json_stack->level++;
1009 EVEL_DEBUG("Stack Push -> %d", json_stack->level);
1010 entry = &json_stack->entry[json_stack->level];
1011 entry->json_count = 0;
1012 entry->num_required = num_required;
1013 entry->json_state = new_state;
1014 entry->json_key = NULL;
1024 /**************************************************************************//**
1025 * Pop any stack entries which have collected the required number of items.
1027 * @param json_stack The stack.
1028 *****************************************************************************/
1029 void evel_stack_pop(EVEL_JSON_STACK * const json_stack)
1031 EVEL_JSON_STACK_ENTRY * entry;
1036 /***************************************************************************/
1037 /* Check preconditions. */
1038 /***************************************************************************/
1039 assert(json_stack != NULL);
1040 assert(json_stack->level >= 0);
1041 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1043 entry = &json_stack->entry[json_stack->level];
1044 while ((json_stack->level > 0) && (entry->json_count == entry->num_required))
1046 key = entry->json_key;
1048 switch (evel_json_command_state)
1050 case EVEL_JCS_COMMAND_LIST:
1051 evel_set_command_state(EVEL_JCS_START);
1054 case EVEL_JCS_COMMAND_LIST_ENTRY:
1055 evel_set_command_state(EVEL_JCS_COMMAND_LIST);
1058 case EVEL_JCS_COMMAND:
1059 evel_close_command();
1060 evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
1064 evel_close_throttle_spec();
1065 evel_set_command_state(EVEL_JCS_COMMAND);
1068 case EVEL_JCS_FIELD_NAMES:
1069 evel_set_command_state(EVEL_JCS_SPEC);
1072 case EVEL_JCS_PAIRS_LIST:
1073 evel_set_command_state(EVEL_JCS_SPEC);
1076 case EVEL_JCS_PAIRS_LIST_ENTRY:
1077 evel_close_nv_pairs_list_entry();
1078 evel_set_command_state(EVEL_JCS_PAIRS_LIST);
1081 case EVEL_JCS_NV_PAIR_NAMES:
1082 evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
1089 /*************************************************************************/
1090 /* Free off any key that was duplicated and stored. */
1091 /*************************************************************************/
1095 entry->json_key = NULL;
1098 /*************************************************************************/
1099 /* We just reached the required number of key-value pairs or items, so */
1100 /* pop the stack. */
1101 /*************************************************************************/
1102 json_stack->level--;
1105 EVEL_DEBUG("Stack Pop -> %d", json_stack->level);
1107 /*************************************************************************/
1108 /* We just completed collection of an ITEM (within an ARRAY) or a VALUE */
1109 /* (within an OBJECT). Either way, we need to count it. */
1110 /*************************************************************************/
1111 entry->json_count++;
1113 /*************************************************************************/
1114 /* If we just completed a VALUE, then we expect the next element to be a */
1115 /* key, if there is a next element. */
1116 /*************************************************************************/
1117 if (entry->json_state == EVEL_JSON_VALUE)
1119 entry->json_state = EVEL_JSON_KEY;
1126 /**************************************************************************//**
1127 * Pop all stack entries, freeing any memory as we go.
1129 * @param json_stack The stack.
1130 *****************************************************************************/
1131 void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack)
1133 EVEL_JSON_STACK_ENTRY * entry;
1137 /***************************************************************************/
1138 /* Check preconditions. */
1139 /***************************************************************************/
1140 assert(json_stack != NULL);
1141 assert(json_stack->level >= 0);
1142 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1144 entry = &json_stack->entry[json_stack->level];
1145 while ((json_stack->level > 0))
1147 /*************************************************************************/
1148 /* Free off any key that was duplicated and stored. */
1149 /*************************************************************************/
1150 if (entry->json_key != NULL)
1152 free(entry->json_key);
1153 entry->json_key = NULL;
1156 /*************************************************************************/
1157 /* We just reached the required number of key-value pairs or items, so */
1158 /* pop the stack. */
1159 /*************************************************************************/
1160 json_stack->level--;
1164 /***************************************************************************/
1165 /* If we hit EVEL_JSON_STACK_DEPTH, we exit the loop and can leave these */
1166 /* values hanging - so clean them up. */
1167 /***************************************************************************/
1168 if (evel_command_type_value != NULL)
1170 free(evel_command_type_value);
1171 evel_command_type_value = NULL;
1173 if (evel_measurement_interval_value != NULL)
1175 free(evel_measurement_interval_value);
1176 evel_measurement_interval_value = NULL;
1178 if (evel_throttle_spec_domain_value != NULL)
1180 free(evel_throttle_spec_domain_value);
1181 evel_throttle_spec_domain_value = NULL;
1183 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1184 if (evel_temp_throttle != NULL)
1186 evel_throttle_free(evel_temp_throttle);
1187 evel_temp_throttle = NULL;
1193 /**************************************************************************//**
1194 * Store a key in the JSON stack.
1196 * We always store the most recent key at each level in the stack.
1198 * @param json_stack The stack.
1199 * @param token The token holding the key.
1200 *****************************************************************************/
1201 void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
1202 const jsmntok_t * const token)
1204 EVEL_JSON_STACK_ENTRY * entry;
1208 /***************************************************************************/
1209 /* Check preconditions. */
1210 /***************************************************************************/
1211 assert(json_stack != NULL);
1212 assert(json_stack->level >= 0);
1213 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1215 /***************************************************************************/
1216 /* Free any previously stored key, replacing it with the new one. */
1217 /***************************************************************************/
1218 entry = &json_stack->entry[json_stack->level];
1219 if (entry->json_key != NULL)
1221 free(entry->json_key);
1223 entry->json_key = evel_stack_strdup(json_stack->chunk, token);
1225 /***************************************************************************/
1226 /* Switch state to collecting the corresponding value. */
1227 /***************************************************************************/
1228 entry->json_state = EVEL_JSON_VALUE;
1230 EVEL_DEBUG("Stored key: %s", entry->json_key);
1234 /**************************************************************************//**
1235 * Store a value in the JSON stack.
1237 * @param json_stack The stack.
1238 * @param token The token holding the value.
1239 *****************************************************************************/
1240 void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
1241 const jsmntok_t * const token)
1243 EVEL_JSON_STACK_ENTRY * entry;
1249 /***************************************************************************/
1250 /* Check preconditions. */
1251 /***************************************************************************/
1252 assert(json_stack != NULL);
1253 assert(json_stack->level >= 0);
1254 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1256 /***************************************************************************/
1257 /* Based on the (key, state), work out whether we're expecting a value, */
1258 /* then store or ignore it as required. */
1259 /***************************************************************************/
1260 entry = &json_stack->entry[json_stack->level];
1261 value = evel_stack_strdup(json_stack->chunk, token);
1263 EVEL_DEBUG("Store value: %s", value);
1265 switch (evel_json_command_state)
1267 case EVEL_JCS_COMMAND:
1268 if (strcmp(entry->json_key, "commandType") == 0)
1270 evel_command_type_value = value;
1273 else if (strcmp(entry->json_key, "measurementInterval") == 0)
1275 evel_measurement_interval_value = value;
1281 if (strcmp(entry->json_key, "eventDomain") == 0)
1283 evel_throttle_spec_domain_value = value;
1288 case EVEL_JCS_PAIRS_LIST_ENTRY:
1289 if (strcmp(entry->json_key, "nvPairFieldName") == 0)
1291 evel_store_nv_pair_field_name(value);
1297 EVEL_DEBUG("Ignoring value in state: %s",
1298 evel_jcs_strings[evel_json_command_state]);
1304 EVEL_DEBUG("Ignored value: %s", value);
1308 /***************************************************************************/
1309 /* Switch state to another key. */
1310 /***************************************************************************/
1311 entry->json_state = EVEL_JSON_KEY;
1313 /***************************************************************************/
1314 /* Count the key-value pair. */
1315 /***************************************************************************/
1316 entry->json_count++;
1321 /**************************************************************************//**
1322 * Store an item in the JSON stack - a string or primitive in an array.
1324 * @param json_stack The stack.
1325 * @param token The token holding the item.
1326 *****************************************************************************/
1327 void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
1328 const jsmntok_t * const token)
1330 EVEL_JSON_STACK_ENTRY * entry;
1336 /***************************************************************************/
1337 /* Check preconditions. */
1338 /***************************************************************************/
1339 assert(json_stack != NULL);
1340 assert(json_stack->level >= 0);
1341 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1343 /***************************************************************************/
1344 /* Based on the state, work out whether we're expecting an item, then */
1345 /* store or ignore it as required. */
1346 /***************************************************************************/
1347 entry = &json_stack->entry[json_stack->level];
1348 item = evel_stack_strdup(json_stack->chunk, token);
1350 EVEL_DEBUG("Store item: %s", item);
1352 switch (evel_json_command_state)
1354 case EVEL_JCS_NV_PAIR_NAMES:
1355 evel_store_nv_pair_name(item);
1359 case EVEL_JCS_FIELD_NAMES:
1360 evel_store_suppressed_field_name(item);
1365 EVEL_DEBUG("Ignoring item in state: %s",
1366 evel_jcs_strings[evel_json_command_state]);
1372 EVEL_DEBUG("Ignored item: %s", item);
1376 /***************************************************************************/
1377 /* We need another item. This is purely defensive. */
1378 /***************************************************************************/
1379 entry->json_state = EVEL_JSON_ITEM;
1381 /***************************************************************************/
1382 /* Count the item. */
1383 /***************************************************************************/
1384 entry->json_count++;
1387 /**************************************************************************//**
1388 * Set the JSON command state to a new value.
1390 * @param new_state The new state to set.
1391 *****************************************************************************/
1392 void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state)
1396 /***************************************************************************/
1397 /* Check preconditions. */
1398 /***************************************************************************/
1399 assert(evel_json_command_state < EVEL_JCS_MAX);
1400 assert(new_state < EVEL_JCS_MAX);
1402 /***************************************************************************/
1403 /* Provide common debug, and set the new state. */
1404 /***************************************************************************/
1405 EVEL_DEBUG("Command State: %s -> %s",
1406 evel_jcs_strings[evel_json_command_state],
1407 evel_jcs_strings[new_state]);
1408 evel_json_command_state = new_state;
1413 /**************************************************************************//**
1414 * Produce debug output from a JSON token.
1416 * @param chunk Memory chunk containing the JSON buffer.
1417 * @param token Token to dump.
1418 *****************************************************************************/
1419 void evel_debug_token(const MEMORY_CHUNK * const chunk,
1420 const jsmntok_t * const token)
1426 /***************************************************************************/
1427 /* Check preconditions. */
1428 /***************************************************************************/
1429 assert(token->type > 0);
1430 assert(token->type < JSON_TOKEN_TYPES);
1432 /***************************************************************************/
1433 /* Log the token, leaving it in the state in which it started. */
1434 /***************************************************************************/
1435 temp_char = chunk->memory[token->end];
1436 chunk->memory[token->end] = '\0';
1437 EVEL_DEBUG("JSON token type: %s", evel_json_token_strings[token->type]);
1438 EVEL_DEBUG("JSON token: %s", chunk->memory + token->start);
1439 chunk->memory[token->end] = temp_char;
1444 /**************************************************************************//**
1445 * Post a response to the commandList.
1447 * @param post Memory chunk in which to post a response.
1448 *****************************************************************************/
1449 void evel_command_list_response(MEMORY_CHUNK * const post)
1455 /***************************************************************************/
1456 /* Check preconditions. */
1457 /***************************************************************************/
1458 assert(post != NULL);
1459 assert(post->memory == NULL);
1461 if (evel_provide_throttling_state)
1463 EVEL_DEBUG("Provide throttling state");
1465 /*************************************************************************/
1466 /* Encode the response, making it printf-able for debug. */
1467 /*************************************************************************/
1468 json_post = malloc(EVEL_MAX_JSON_BODY);
1469 assert(json_post != NULL);
1470 post->size = evel_json_encode_throttle(json_post, EVEL_MAX_JSON_BODY - 1);
1471 post->memory = json_post;
1472 post->memory[post->size] = '\0';
1473 evel_provide_throttling_state = false;
1479 /**************************************************************************//**
1480 * Encode the full throttling specification according to AT&T's schema.
1482 * @param json Pointer to where to store the JSON encoded data.
1483 * @param max_size Size of storage available in json_body.
1484 * @returns Number of bytes actually written.
1485 *****************************************************************************/
1486 int evel_json_encode_throttle(char * const json, const int max_size)
1495 /***************************************************************************/
1496 /* Check preconditions. */
1497 /***************************************************************************/
1498 assert(json != NULL);
1499 assert(max_size > 0);
1501 /***************************************************************************/
1502 /* Work out if we're throttled. */
1503 /***************************************************************************/
1505 for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1507 if (evel_throttle_spec[domain] != NULL)
1513 /***************************************************************************/
1514 /* Encode the response. */
1515 /***************************************************************************/
1517 offset += snprintf(json + offset, max_size - offset,
1518 "{\"eventThrottlingState\": {");
1519 offset += snprintf(json + offset, max_size - offset,
1520 "\"eventThrottlingMode\": \"%s\"",
1521 throttled ? "throttled" : "normal");
1524 offset += snprintf(json + offset, max_size - offset,
1525 ", \"eventDomainThrottleSpecificationList\": [");
1527 domain_added = false;
1528 for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1530 if (evel_throttle_spec[domain] != NULL)
1534 offset += snprintf(json + offset, max_size - offset, ", ");
1537 offset += evel_json_encode_throttle_spec(json + offset,
1540 domain_added = true;
1544 offset += snprintf(json + offset, max_size - offset, "]");
1547 offset += snprintf(json + offset, max_size - offset, "}}");
1554 /**************************************************************************//**
1555 * Encode a throttling specification for a domain.
1557 * @param json Pointer to where to store the JSON encoded data.
1558 * @param max_size Size of storage available in json_body.
1559 * @returns Number of bytes actually written.
1560 *****************************************************************************/
1561 int evel_json_encode_throttle_spec(char * const json,
1563 const EVEL_EVENT_DOMAINS domain)
1566 EVEL_THROTTLE_SPEC * throttle_spec;
1567 DLIST_ITEM * dlist_item;
1570 /***************************************************************************/
1571 /* Check preconditions. */
1572 /***************************************************************************/
1573 assert(domain >= EVEL_DOMAIN_FAULT);
1574 assert(domain < EVEL_MAX_DOMAINS);
1575 assert(evel_throttle_spec[domain] != NULL);
1577 throttle_spec = evel_throttle_spec[domain];
1579 /***************************************************************************/
1580 /* Encode the domain. */
1581 /***************************************************************************/
1583 offset += snprintf(json + offset, max_size - offset,
1585 offset += snprintf(json + offset, max_size - offset,
1586 "\"eventDomain\": \"%s\"",
1587 evel_domain_strings[domain]);
1589 /***************************************************************************/
1590 /* Encode "suppressedFieldNames". */
1591 /***************************************************************************/
1592 dlist_item = dlist_get_first(&throttle_spec->suppressed_field_names);
1593 if (dlist_item != NULL)
1595 offset += snprintf(json + offset, max_size - offset,
1596 ", \"suppressedFieldNames\": [");
1597 while (dlist_item != NULL)
1599 char * suppressed_field = dlist_item->item;
1600 assert(suppressed_field != NULL);
1602 offset += snprintf(json + offset, max_size - offset,
1603 "\"%s\"", suppressed_field);
1604 dlist_item = dlist_get_next(dlist_item);
1605 if (dlist_item != NULL)
1607 offset += snprintf(json + offset, max_size - offset, ", ");
1611 offset += snprintf(json + offset, max_size - offset, "]");
1614 /***************************************************************************/
1615 /* Encode "suppressedNvPairsList". */
1616 /***************************************************************************/
1617 dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
1618 if (dlist_item != NULL)
1620 offset += snprintf(json + offset, max_size - offset,
1621 ", \"suppressedNvPairsList\": [");
1622 while (dlist_item != NULL)
1624 offset += evel_json_encode_nv_pairs(json + offset,
1627 dlist_item = dlist_get_next(dlist_item);
1628 if (dlist_item != NULL)
1630 offset += snprintf(json + offset, max_size - offset, ", ");
1634 offset += snprintf(json + offset, max_size - offset, "]");
1637 offset += snprintf(json + offset, max_size - offset, "}");
1644 /**************************************************************************//**
1645 * Encode a single "suppressedNvPairsListEntry".
1647 * @param json Pointer to where to store the JSON encoded data.
1648 * @param max_size Size of storage available in json_body.
1649 * @returns Number of bytes actually written.
1650 *****************************************************************************/
1651 int evel_json_encode_nv_pairs(char * const json,
1653 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
1655 DLIST_ITEM * dlist_item;
1659 /***************************************************************************/
1660 /* Check preconditions. */
1661 /***************************************************************************/
1662 assert(nv_pairs != NULL);
1663 assert(nv_pairs->nv_pair_field_name != NULL);
1664 assert(!dlist_is_empty(&nv_pairs->suppressed_nv_pair_names));
1666 /***************************************************************************/
1668 /***************************************************************************/
1670 offset += snprintf(json + offset, max_size - offset, "{");
1671 offset += snprintf(json + offset, max_size - offset,
1672 "\"nvPairFieldName\": \"%s\"",
1673 nv_pairs->nv_pair_field_name);
1674 dlist_item = dlist_get_first(&nv_pairs->suppressed_nv_pair_names);
1675 offset += snprintf(json + offset, max_size - offset,
1676 ", \"suppressedNvPairNames\": [");
1677 while (dlist_item != NULL)
1679 name = dlist_item->item;
1680 assert(name != NULL);
1681 offset += snprintf(json + offset, max_size - offset, "\"%s\"", name);
1682 dlist_item = dlist_get_next(dlist_item);
1683 if (dlist_item != NULL)
1685 offset += snprintf(json + offset, max_size - offset, ", ");
1688 offset += snprintf(json + offset, max_size - offset, "]");
1689 offset += snprintf(json + offset, max_size - offset, "}");
1696 /**************************************************************************//**
1697 * Method called when we open a "command" object.
1698 *****************************************************************************/
1699 void evel_open_command()
1703 /***************************************************************************/
1704 /* Make some assertions. */
1705 /***************************************************************************/
1706 assert(evel_command_type_value == NULL);
1707 assert(evel_measurement_interval_value == NULL);
1712 /**************************************************************************//**
1713 * Method called when we close a "command" object.
1714 *****************************************************************************/
1715 void evel_close_command()
1719 /***************************************************************************/
1720 /* If a commandType was provided, fan out and handle it now what we have */
1721 /* fathered all related information. */
1723 /* Note that we handle throttling specification and measurement interval */
1724 /* updates immediately on closing the command (not the list). We could */
1725 /* reject *all* commands in a list if any of them are invalid, but we are */
1726 /* take a best-effort strategy here - any valid-looking command gets */
1727 /* implemented regardless of what follows. */
1728 /***************************************************************************/
1729 if (evel_command_type_value != NULL)
1731 EVEL_DEBUG("Closing command %s", evel_command_type_value);
1733 if (strcmp(evel_command_type_value, "provideThrottlingState") == 0)
1735 evel_provide_throttling_state = true;
1737 else if (strcmp(evel_command_type_value, "throttlingSpecification") == 0)
1739 evel_set_throttling_spec();
1741 else if (strcmp(evel_command_type_value, "measurementIntervalChange") == 0)
1743 evel_set_measurement_interval();
1747 EVEL_ERROR("Ignoring unknown commandType: %s\n",
1748 evel_command_type_value);
1751 /*************************************************************************/
1752 /* Free the captured "commandType" value. */
1753 /*************************************************************************/
1754 free(evel_command_type_value);
1755 evel_command_type_value = NULL;
1758 /***************************************************************************/
1759 /* There could be an unused working throttle spec at this point - if the */
1760 /* "throttlingSpecification" commandType was not provided, or an invalid */
1761 /* domain was provided, or was not provided at all. */
1762 /***************************************************************************/
1763 if (evel_temp_throttle != NULL)
1765 evel_throttle_free(evel_temp_throttle);
1766 evel_temp_throttle = NULL;
1769 /***************************************************************************/
1770 /* Similarly, the domain could be set. */
1771 /***************************************************************************/
1772 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1774 /***************************************************************************/
1775 /* There could be an unused measurement interval value at this point - if */
1776 /* the "measurementIntervalChange" command was not provided. */
1777 /***************************************************************************/
1778 if (evel_measurement_interval_value != NULL)
1780 free(evel_measurement_interval_value);
1781 evel_measurement_interval_value = NULL;
1787 /**************************************************************************//**
1788 * Set the provided throttling specification, when the command closes.
1789 *****************************************************************************/
1790 void evel_set_throttling_spec()
1794 if ((evel_throttle_spec_domain >= 0) &&
1795 (evel_throttle_spec_domain < EVEL_MAX_DOMAINS))
1797 EVEL_DEBUG("Updating throttle spec for domain: %s",
1798 evel_domain_strings[evel_throttle_spec_domain]);
1800 /*************************************************************************/
1801 /* Free off the previous throttle specification for the domain, if there */
1803 /*************************************************************************/
1804 if (evel_throttle_spec[evel_throttle_spec_domain] != NULL)
1806 evel_throttle_free(evel_throttle_spec[evel_throttle_spec_domain]);
1809 /*************************************************************************/
1810 /* Finalize the working throttling spec, if there is one. */
1811 /*************************************************************************/
1812 if (evel_temp_throttle != NULL)
1814 evel_throttle_finalize(evel_temp_throttle);
1817 /*************************************************************************/
1818 /* Replace the throttle specification for the domain with the working */
1819 /* throttle specification. This could be NULL, if an empty throttle */
1820 /* specification has been received for a domain. */
1821 /*************************************************************************/
1822 evel_throttle_spec[evel_throttle_spec_domain] = evel_temp_throttle;
1823 evel_temp_throttle = NULL;
1829 /**************************************************************************//**
1830 * Set the provided measurement interval, when the command closes.
1831 *****************************************************************************/
1832 void evel_set_measurement_interval()
1836 if (evel_measurement_interval_value != NULL)
1838 const long int value = strtol(evel_measurement_interval_value, NULL, 10);
1840 if ((value >= 0) && (value <= INT_MAX))
1842 /***********************************************************************/
1843 /* Lock, update, unlock. */
1844 /***********************************************************************/
1845 EVEL_DEBUG("Updating measurement interval to %d\n", value);
1847 pthread_mutex_lock(&evel_measurement_interval_mutex);
1848 evel_measurement_interval = value;
1849 pthread_mutex_unlock(&evel_measurement_interval_mutex);
1853 EVEL_ERROR("Ignoring invalid measurement interval: %s",
1854 evel_measurement_interval_value);
1861 /**************************************************************************//**
1862 * Method called when we open an "eventDomainThrottleSpecification" object.
1863 *****************************************************************************/
1864 void evel_open_throttle_spec()
1868 /***************************************************************************/
1869 /* Check preconditions. */
1870 /***************************************************************************/
1871 assert(evel_throttle_spec_domain_value == NULL);
1872 assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
1873 assert(evel_temp_throttle == NULL);
1875 /***************************************************************************/
1876 /* Allocate and initialize an ::EVEL_THROTTLE_SPEC in which to hold */
1877 /* captured JSON elements. */
1878 /***************************************************************************/
1879 evel_temp_throttle = malloc(sizeof(EVEL_THROTTLE_SPEC));
1880 assert(evel_temp_throttle != NULL);
1881 dlist_initialize(&evel_temp_throttle->suppressed_field_names);
1882 dlist_initialize(&evel_temp_throttle->suppressed_nv_pairs_list);
1883 evel_temp_throttle->hash_field_names = NULL;
1884 evel_temp_throttle->hash_nv_pairs_list = NULL;
1889 /**************************************************************************//**
1890 * Method called when we close an "eventDomainThrottleSpecification" object.
1891 *****************************************************************************/
1892 void evel_close_throttle_spec()
1896 /***************************************************************************/
1897 /* Decode, free and blank a captured event domain value. */
1898 /***************************************************************************/
1899 if (evel_throttle_spec_domain_value != NULL)
1901 evel_throttle_spec_domain =
1902 evel_decode_domain(evel_throttle_spec_domain_value);
1903 free(evel_throttle_spec_domain_value);
1904 evel_throttle_spec_domain_value = NULL;
1907 /***************************************************************************/
1908 /* Free off an empty working throttle spec, to stop it being used. This */
1909 /* state should be represented by a NULL pointer for the domain. */
1910 /***************************************************************************/
1911 if (evel_temp_throttle != NULL)
1913 if (dlist_is_empty(&evel_temp_throttle->suppressed_field_names) &&
1914 dlist_is_empty(&evel_temp_throttle->suppressed_nv_pairs_list))
1916 free(evel_temp_throttle);
1917 evel_temp_throttle = NULL;
1924 /**************************************************************************//**
1925 * Convert a value for an "eventDomain" into an ::EVEL_EVENT_DOMAINS.
1927 * @param domain_value The domain string value to decode.
1928 * @returns The matching ::EVEL_EVENT_DOMAINS, or ::EVEL_MAX_DOMAINS on error.
1929 *****************************************************************************/
1930 EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value)
1932 EVEL_EVENT_DOMAINS result;
1937 /***************************************************************************/
1938 /* Check preconditions. */
1939 /***************************************************************************/
1940 assert(domain_value != NULL);
1942 result = EVEL_MAX_DOMAINS;
1943 for (ii = EVEL_DOMAIN_FAULT; ii < EVEL_MAX_DOMAINS; ii++)
1945 assert(evel_domain_strings[ii] != NULL);
1946 if (strcmp(evel_domain_strings[ii], domain_value) == 0)
1957 /**************************************************************************//**
1958 * Method called when we open a "suppressedNvPairsListEntry" object.
1959 *****************************************************************************/
1960 void evel_open_nv_pairs_list_entry()
1962 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1966 /***************************************************************************/
1967 /* Check preconditions. */
1968 /***************************************************************************/
1969 assert(evel_temp_throttle != NULL);
1971 /***************************************************************************/
1972 /* Allocate and initialize an ::EVEL_SUPPRESSED_NV_PAIRS, and add it to */
1974 /***************************************************************************/
1975 nv_pairs = malloc(sizeof(EVEL_SUPPRESSED_NV_PAIRS));
1976 assert(nv_pairs != NULL);
1977 nv_pairs->nv_pair_field_name = NULL;
1978 dlist_initialize(&nv_pairs->suppressed_nv_pair_names);
1979 nv_pairs->hash_nv_pair_names = NULL;
1980 dlist_push_last(&evel_temp_throttle->suppressed_nv_pairs_list, nv_pairs);
1985 /**************************************************************************//**
1986 * Method called when we close a "suppressedNvPairsListEntry" object.
1987 *****************************************************************************/
1988 void evel_close_nv_pairs_list_entry()
1990 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1991 EVEL_SUPPRESSED_NV_PAIRS * popped;
1995 /***************************************************************************/
1996 /* Get the latest nv pairs. This also performs the required checks. */
1997 /***************************************************************************/
1998 nv_pairs = evel_get_last_nv_pairs();
2000 /***************************************************************************/
2001 /* For a "suppressedNvPairsListEntry" to have any meaning, we need both */
2002 /* "nvPairFieldName" and "suppressedNvPairNames". If we don't, then pop */
2003 /* and free whatever we just collected. */
2004 /***************************************************************************/
2005 if ((nv_pairs->nv_pair_field_name == NULL) ||
2006 dlist_is_empty(&nv_pairs->suppressed_nv_pair_names))
2008 popped = dlist_pop_last(&evel_temp_throttle->suppressed_nv_pairs_list);
2009 assert(popped == nv_pairs);
2010 evel_throttle_free_nv_pair(popped);
2016 /**************************************************************************//**
2017 * Store an "nvPairFieldName" value in the working throttle spec.
2019 * @param value The value to store.
2020 *****************************************************************************/
2021 void evel_store_nv_pair_field_name(char * const value)
2023 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2027 /***************************************************************************/
2028 /* Get the latest nv pairs. This also performs the required checks. */
2029 /***************************************************************************/
2030 nv_pairs = evel_get_last_nv_pairs();
2032 /***************************************************************************/
2033 /* Store the value. */
2034 /***************************************************************************/
2035 nv_pairs->nv_pair_field_name = value;
2040 /**************************************************************************//**
2041 * Store a "suppressedNvPairNames" item in the working throttle spec.
2043 * @param item The item to store.
2044 *****************************************************************************/
2045 void evel_store_nv_pair_name(char * const item)
2047 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2051 /***************************************************************************/
2052 /* Get the latest nv pairs. This also performs the required checks. */
2053 /***************************************************************************/
2054 nv_pairs = evel_get_last_nv_pairs();
2056 /***************************************************************************/
2057 /* Store the item. */
2058 /***************************************************************************/
2059 dlist_push_last(&nv_pairs->suppressed_nv_pair_names, item);
2064 /**************************************************************************//**
2065 * Store a "suppressedFieldNames" item in the working throttle spec.
2067 * @param item The item to store.
2068 *****************************************************************************/
2069 void evel_store_suppressed_field_name(char * const item)
2073 /***************************************************************************/
2074 /* Check preconditions. */
2075 /***************************************************************************/
2076 assert(evel_temp_throttle != NULL);
2078 /***************************************************************************/
2079 /* Store the item. */
2080 /***************************************************************************/
2081 dlist_push_last(&evel_temp_throttle->suppressed_field_names, item);
2086 /**************************************************************************//**
2087 * Get the last added suppressed nv pairs list entry in the working spec.
2089 * @returns The last entry.
2090 *****************************************************************************/
2091 EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs()
2093 DLIST_ITEM * dlist_item;
2094 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2098 /***************************************************************************/
2099 /* Check preconditions. */
2100 /***************************************************************************/
2101 assert(evel_temp_throttle != NULL);
2103 /***************************************************************************/
2104 /* Get the pair that was added when we opened the list entry. */
2105 /***************************************************************************/
2106 dlist_item = dlist_get_last(&evel_temp_throttle->suppressed_nv_pairs_list);
2107 assert(dlist_item != NULL);
2108 nv_pairs = dlist_item->item;
2109 assert(nv_pairs != NULL);