1 /*************************************************************************//**
3 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 ****************************************************************************/
18 /**************************************************************************//**
22 * Simple event manager that is responsible for taking events (Heartbeats,
23 * Faults and Measurements) from the ring-buffer and posting them to the API.
25 ****************************************************************************/
35 #include "evel_throttle.h"
37 /*****************************************************************************/
38 /* The Event Throttling State for all domains, indexed by */
39 /* ::EVEL_EVENT_DOMAINS, corresponding to JSON eventDomain. */
41 /* A given domain is in a throttled state if ::evel_throttle_spec is */
43 /*****************************************************************************/
44 static EVEL_THROTTLE_SPEC * evel_throttle_spec[EVEL_MAX_DOMAINS];
46 /*****************************************************************************/
47 /* The current measurement interval. Default: MEASUREMENT_INTERVAL_UKNOWN. */
48 /* Must be protected by evel_measurement_interval_mutex. */
49 /*****************************************************************************/
50 static int evel_measurement_interval;
52 /*****************************************************************************/
53 /* Mutex protecting evel_measurement_interval from contention between an */
54 /* EVEL client reading it, and the EVEL event handler updating it. */
55 /*****************************************************************************/
56 static pthread_mutex_t evel_measurement_interval_mutex;
58 /*****************************************************************************/
59 /* Flag stating that we have received a "provideThrottlingState" command. */
60 /* Set during JSON processing and cleared on sending the throttling state. */
61 /*****************************************************************************/
62 static bool evel_provide_throttling_state;
64 /*****************************************************************************/
65 /* Holder for the "commandType" value during JSON processing. */
66 /*****************************************************************************/
67 static char * evel_command_type_value;
69 /*****************************************************************************/
70 /* Holder for the "measurementInterval" value during JSON processing. */
71 /*****************************************************************************/
72 static char * evel_measurement_interval_value;
74 /*****************************************************************************/
75 /* Holder for the "eventDomain" value during JSON processing. */
76 /*****************************************************************************/
77 static char * evel_throttle_spec_domain_value;
79 /*****************************************************************************/
80 /* Decoded version of ::evel_throttle_spec_domain_value. */
81 /*****************************************************************************/
82 static EVEL_EVENT_DOMAINS evel_throttle_spec_domain;
84 /*****************************************************************************/
85 /* During JSON processing of a single throttling specification, we collect */
86 /* parameters in this working ::EVEL_THROTTLE_SPEC */
87 /*****************************************************************************/
88 static EVEL_THROTTLE_SPEC * evel_temp_throttle;
90 /*****************************************************************************/
91 /* State tracking our progress through the command list */
92 /*****************************************************************************/
93 EVEL_JSON_COMMAND_STATE evel_json_command_state;
95 /*****************************************************************************/
96 /* Debug strings for ::EVEL_JSON_COMMAND_STATE. */
97 /*****************************************************************************/
98 static const char * const evel_jcs_strings[EVEL_JCS_MAX] = {
100 "EVEL_JCS_COMMAND_LIST",
101 "EVEL_JCS_COMMAND_LIST_ENTRY",
104 "EVEL_JCS_FIELD_NAMES",
105 "EVEL_JCS_PAIRS_LIST",
106 "EVEL_JCS_PAIRS_LIST_ENTRY",
107 "EVEL_JCS_NV_PAIR_NAMES"
110 /*****************************************************************************/
111 /* Debug strings for JSON token type. */
112 /*****************************************************************************/
113 #define JSON_TOKEN_TYPES (JSMN_PRIMITIVE + 1)
114 static const char * const evel_json_token_strings[JSON_TOKEN_TYPES] = {
122 /*****************************************************************************/
123 /* Debug strings for JSON domains. */
124 /*****************************************************************************/
125 static const char * evel_domain_strings[EVEL_MAX_DOMAINS] = {
129 "measurementsForVfScaling",
141 /*****************************************************************************/
142 /* Local prototypes. */
143 /*****************************************************************************/
144 static void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec);
145 static struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys);
146 static void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec);
147 static void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
148 static void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
149 const MEMORY_CHUNK * const chunk);
150 static bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
151 const int num_required,
152 const EVEL_JSON_STATE new_state);
153 static void evel_stack_pop(EVEL_JSON_STACK * const json_stack);
154 static void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack);
155 static char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
156 const jsmntok_t * const token);
157 static void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
158 const jsmntok_t * const token);
159 static void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
160 const jsmntok_t * const token);
161 static void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
162 const jsmntok_t * const token);
163 static void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state);
164 static void evel_debug_token(const MEMORY_CHUNK * const chunk,
165 const jsmntok_t * const token);
166 static void evel_command_list_response(MEMORY_CHUNK * const post);
167 static int evel_json_encode_throttle(char * const json, const int max_size);
168 static int evel_json_encode_throttle_spec(char * const json,
170 const EVEL_EVENT_DOMAINS domain);
171 static int evel_json_encode_nv_pairs(char * const json,
173 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
174 static void evel_close_command();
175 static void evel_open_command();
176 static void evel_set_throttling_spec();
177 static void evel_set_measurement_interval();
178 static void evel_open_throttle_spec();
179 static void evel_close_throttle_spec();
180 static EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value);
181 static void evel_open_nv_pairs_list_entry();
182 static void evel_close_nv_pairs_list_entry();
183 static void evel_store_nv_pair_field_name(char * const value);
184 static void evel_store_nv_pair_name(char * const item);
185 static void evel_store_suppressed_field_name(char * const item);
186 static EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs();
188 /**************************************************************************//**
189 * Return the current measurement interval provided by the Event Listener.
191 * @returns The current measurement interval
192 * @retval EVEL_MEASUREMENT_INTERVAL_UKNOWN (0) - interval has not been
194 *****************************************************************************/
195 int evel_get_measurement_interval()
201 /***************************************************************************/
202 /* Lock, read, unlock. */
203 /***************************************************************************/
204 pthread_mutex_lock(&evel_measurement_interval_mutex);
205 result = evel_measurement_interval;
206 pthread_mutex_unlock(&evel_measurement_interval_mutex);
213 /**************************************************************************//**
214 * Return the ::EVEL_THROTTLE_SPEC for a given domain.
216 * @param domain The domain for which to return state.
217 *****************************************************************************/
218 EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain)
220 EVEL_THROTTLE_SPEC * result;
224 /***************************************************************************/
225 /* Check preconditions. */
226 /***************************************************************************/
227 assert(domain < EVEL_MAX_DOMAINS);
229 result = evel_throttle_spec[domain];
236 /**************************************************************************//**
237 * Determine whether a field_name should be suppressed.
239 * @param throttle_spec Throttle specification for the domain being encoded.
240 * @param field_name The field name to encoded or suppress.
241 * @return true if the field_name should be suppressed, false otherwise.
242 *****************************************************************************/
243 bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC * throttle_spec,
244 const char * const field_name)
246 bool suppress = false;
250 /***************************************************************************/
251 /* Check preconditions. */
252 /***************************************************************************/
253 assert(field_name != NULL);
255 /***************************************************************************/
256 /* If the throttle spec and hash table exist, query the field_names table. */
257 /***************************************************************************/
258 if ((throttle_spec != NULL) && (throttle_spec->hash_field_names != NULL))
262 hash_query.key = (char * const) field_name;
263 suppress = (hsearch_r(hash_query,
266 throttle_spec->hash_field_names) != 0);
274 /**************************************************************************//**
275 * Determine whether a name-value pair should be allowed (not suppressed).
277 * @param throttle_spec Throttle specification for the domain being encoded.
278 * @param field_name The field name holding the name-value pairs.
279 * @param name The name of the name-value pair to encoded or suppress.
280 * @return true if the name-value pair should be suppressed, false otherwise.
281 *****************************************************************************/
282 bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC * throttle_spec,
283 const char * const field_name,
284 const char * const name)
286 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
288 bool suppress = false;
292 /***************************************************************************/
293 /* Check preconditions. */
294 /***************************************************************************/
295 assert(field_name != NULL);
296 assert(name != NULL);
298 /***************************************************************************/
299 /* If the throttle spec and hash table exist, query the nv_pairs table. */
300 /***************************************************************************/
301 if ((throttle_spec != NULL) && (throttle_spec->hash_nv_pairs_list != NULL))
305 hash_query.key = (char * const) field_name;
306 hit = (hsearch_r(hash_query,
309 throttle_spec->hash_nv_pairs_list) != 0);
312 nv_pairs = hash_result->data;
316 /***************************************************************************/
317 /* If we got a hit, and the nv_pairs and hash table exist, query the */
318 /* nv_pairs table. */
319 /***************************************************************************/
320 if (hit && (nv_pairs != NULL) && (nv_pairs->hash_nv_pair_names != NULL))
324 hash_query.key = (char * const) name;
325 suppress = (hsearch_r(hash_query,
328 nv_pairs->hash_nv_pair_names) != 0);
336 /**************************************************************************//**
337 * Initialize event throttling to the default state.
339 * Called from ::evel_initialize.
340 *****************************************************************************/
341 void evel_throttle_initialize()
348 for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
350 evel_throttle_spec[ii] = NULL;
353 pthread_rc = pthread_mutex_init(&evel_measurement_interval_mutex, NULL);
354 assert(pthread_rc == 0);
356 evel_measurement_interval = EVEL_MEASUREMENT_INTERVAL_UKNOWN;
361 /**************************************************************************//**
362 * Clean up event throttling.
364 * Called from ::evel_terminate.
365 *****************************************************************************/
366 void evel_throttle_terminate()
373 for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
375 if (evel_throttle_spec[ii] != NULL)
377 evel_throttle_free(evel_throttle_spec[ii]);
378 evel_throttle_spec[ii] = NULL;
382 pthread_rc = pthread_mutex_destroy(&evel_measurement_interval_mutex);
383 assert(pthread_rc == 0);
388 /**************************************************************************//**
389 * Finalize a single ::EVEL_THROTTLE_SPEC.
391 * Now that the specification is collected, build hash tables to simplify the
394 * @param throttle_spec The ::EVEL_THROTTLE_SPEC to finalize.
395 *****************************************************************************/
396 void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec)
399 DLIST_ITEM * dlist_item;
404 /***************************************************************************/
405 /* Check preconditions. */
406 /***************************************************************************/
407 assert(throttle_spec != NULL);
409 /***************************************************************************/
410 /* Populate the hash table for suppressed field names. */
411 /***************************************************************************/
412 throttle_spec->hash_field_names =
413 evel_throttle_hash_create(&throttle_spec->suppressed_field_names);
415 /***************************************************************************/
416 /* Create the hash table for suppressed nv pairs. */
417 /***************************************************************************/
418 nv_pairs_count = dlist_count(&throttle_spec->suppressed_nv_pairs_list);
419 if (nv_pairs_count > 0)
421 throttle_spec->hash_nv_pairs_list = calloc(1, sizeof(struct hsearch_data));
422 assert(throttle_spec->hash_nv_pairs_list != NULL);
424 /*************************************************************************/
425 /* Provide plenty of space in the table - see hcreate_r notes. */
426 /*************************************************************************/
427 if (hcreate_r(nv_pairs_count * 2, throttle_spec->hash_nv_pairs_list) == 0)
429 EVEL_ERROR("Failed to create hash table");
430 free(throttle_spec->hash_nv_pairs_list);
431 throttle_spec->hash_nv_pairs_list = NULL;
435 /***************************************************************************/
436 /* Populate the hash tables under suppressed field names. */
437 /***************************************************************************/
438 dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
439 while (dlist_item != NULL)
441 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs = dlist_item->item;
444 /*************************************************************************/
445 /* Set the key to the string, and the item to the nv_pairs. */
446 /*************************************************************************/
447 assert(nv_pairs != NULL);
448 hash_add.key = nv_pairs->nv_pair_field_name;
449 hash_add.data = nv_pairs;
450 hsearch_r(hash_add, ENTER, &add_result, throttle_spec->hash_nv_pairs_list);
452 /*************************************************************************/
453 /* Create the nv_pair_names hash since we're in here. */
454 /*************************************************************************/
455 nv_pairs->hash_nv_pair_names =
456 evel_throttle_hash_create(&nv_pairs->suppressed_nv_pair_names);
458 dlist_item = dlist_get_next(dlist_item);
464 /**************************************************************************//**
465 * Create and populate a hash table from a DLIST of keys.
467 * @param hash_keys Pointer to a DLIST of hash table keys.
468 * @return Pointer to the created hash-table, or NULL on failure.
469 *****************************************************************************/
470 struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys)
473 struct hsearch_data * hash_table;
478 /***************************************************************************/
479 /* Check preconditions. */
480 /***************************************************************************/
481 assert(hash_keys != NULL);
483 /***************************************************************************/
484 /* Count the keys and if there are any, populate the hash table with them. */
485 /***************************************************************************/
486 key_count = dlist_count(hash_keys);
489 EVEL_DEBUG("Populating table for %d keys", key_count);
491 hash_table = calloc(1, sizeof(struct hsearch_data));
492 assert(hash_table != NULL);
494 /*************************************************************************/
495 /* We need to leave plenty of space in the table - see hcreate_r notes. */
496 /*************************************************************************/
497 if (hcreate_r(key_count * 2, hash_table) != 0)
499 DLIST_ITEM * dlist_item;
500 dlist_item = dlist_get_first(hash_keys);
501 while (dlist_item != NULL)
503 assert(dlist_item->item != NULL);
505 /*********************************************************************/
506 /* Set the key and data to the item, which is a string in this case. */
507 /*********************************************************************/
509 hash_add.key = dlist_item->item;
510 hash_add.data = dlist_item->item;
511 hsearch_r(hash_add, ENTER, &add_result, hash_table);
512 dlist_item = dlist_get_next(dlist_item);
517 EVEL_ERROR("Failed to create hash table");
532 /**************************************************************************//**
533 * Free resources associated with a single ::EVEL_THROTTLE_SPEC.
535 * @param throttle_spec The ::EVEL_THROTTLE_SPEC to free.
536 *****************************************************************************/
537 void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec)
540 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
544 /***************************************************************************/
545 /* Check preconditions. */
546 /***************************************************************************/
547 assert(throttle_spec != NULL);
549 /***************************************************************************/
550 /* Free any hash tables. */
551 /***************************************************************************/
552 if (throttle_spec->hash_field_names != NULL)
554 hdestroy_r(throttle_spec->hash_field_names);
555 free(throttle_spec->hash_field_names);
557 if (throttle_spec->hash_nv_pairs_list != NULL)
559 hdestroy_r(throttle_spec->hash_nv_pairs_list);
560 free(throttle_spec->hash_nv_pairs_list);
563 /***************************************************************************/
564 /* Iterate through the linked lists, freeing memory. */
565 /***************************************************************************/
566 field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
567 while (field_name != NULL)
570 field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
573 nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
574 while (nv_pairs != NULL)
576 evel_throttle_free_nv_pair(nv_pairs);
577 nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
585 /**************************************************************************//**
586 * Free resources associated with a single ::EVEL_SUPPRESSED_NV_PAIR.
588 * @param nv_pair The ::EVEL_SUPPRESSED_NV_PAIR to free.
589 *****************************************************************************/
590 void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
592 char * suppressed_name;
596 /***************************************************************************/
597 /* Check preconditions. */
598 /***************************************************************************/
599 assert(nv_pairs != NULL);
601 /***************************************************************************/
602 /* Free any hash tables. */
603 /***************************************************************************/
604 if (nv_pairs->hash_nv_pair_names != NULL)
606 hdestroy_r(nv_pairs->hash_nv_pair_names);
607 free(nv_pairs->hash_nv_pair_names);
610 /***************************************************************************/
611 /* Iterate through the linked lists, freeing memory. */
612 /***************************************************************************/
613 suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
614 while (suppressed_name != NULL)
616 free(suppressed_name);
617 suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
619 if (nv_pairs->nv_pair_field_name != NULL)
621 free(nv_pairs->nv_pair_field_name);
628 /**************************************************************************//**
629 * Handle a JSON response from the listener, as a list of tokens from JSMN.
631 * @param chunk Memory chunk containing the JSON buffer.
632 * @param json_tokens Array of tokens to handle.
633 * @param num_tokens The number of tokens to handle.
634 * @param post The memory chunk in which to place any resulting POST.
635 * @return true if the command was handled, false otherwise.
636 *****************************************************************************/
637 bool evel_handle_command_list(const MEMORY_CHUNK * const chunk,
638 const jsmntok_t * const json_tokens,
639 const int num_tokens,
640 MEMORY_CHUNK * const post)
642 EVEL_JSON_STACK stack;
643 EVEL_JSON_STACK * json_stack = &stack;
644 EVEL_JSON_STACK_ENTRY * entry;
651 /***************************************************************************/
652 /* Check preconditions. */
653 /***************************************************************************/
654 assert(chunk != NULL);
655 assert(json_tokens != NULL);
656 assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS);
658 /***************************************************************************/
659 /* Collect one top-level item. */
660 /***************************************************************************/
661 evel_init_json_stack(json_stack, chunk);
663 /***************************************************************************/
664 /* Initialize JSON processing variables. */
665 /***************************************************************************/
666 evel_provide_throttling_state = false;
667 evel_command_type_value = NULL;
668 evel_measurement_interval_value = NULL;
669 evel_throttle_spec_domain_value = NULL;
670 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
671 evel_temp_throttle = NULL;
672 evel_json_command_state = EVEL_JCS_START;
674 /***************************************************************************/
675 /* Loop through the tokens, keeping a stack of state representing the */
676 /* nested JSON structure (see json_state). We also track our way through */
677 /* the ::EVEL_JSON_COMMAND_STATE as we go. */
678 /***************************************************************************/
679 while (json_ok && (token_index < num_tokens))
681 const jsmntok_t * const token = &json_tokens[token_index];
685 evel_debug_token(chunk, token);
688 /*************************************************************************/
689 /* We may have popped or pushed, so always re-evaluate the stack entry. */
690 /*************************************************************************/
691 entry = &json_stack->entry[json_stack->level];
696 if ((entry->json_state == EVEL_JSON_ITEM) ||
697 (entry->json_state == EVEL_JSON_VALUE))
699 json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_KEY);
703 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
704 entry->json_state, token_index, token->type);
710 if ((entry->json_state == EVEL_JSON_ITEM) ||
711 (entry->json_state == EVEL_JSON_VALUE))
713 json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_ITEM);
717 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
718 entry->json_state, token_index, token->type);
724 if (entry->json_state == EVEL_JSON_KEY)
726 evel_stack_store_key(json_stack, token);
728 else if (entry->json_state == EVEL_JSON_VALUE)
730 evel_stack_store_value(json_stack, token);
732 else if (entry->json_state == EVEL_JSON_ITEM)
734 evel_stack_store_item(json_stack, token);
738 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
739 entry->json_state, token_index, token->type);
745 if (entry->json_state == EVEL_JSON_VALUE)
747 evel_stack_store_value(json_stack, token);
749 else if (entry->json_state == EVEL_JSON_ITEM)
751 evel_stack_store_item(json_stack, token);
755 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
756 entry->json_state, token_index, token->type);
763 EVEL_ERROR("Unexpected JSON format at token %d (%d)",
764 token_index, token->type);
769 /*************************************************************************/
770 /* Pop the stack if we're counted enough nested items. */
771 /*************************************************************************/
772 evel_stack_pop(json_stack);
777 /***************************************************************************/
778 /* Cleanup the stack - we may have exited without winding it back, if the */
779 /* input was not well formed. */
780 /***************************************************************************/
781 evel_stack_cleanup(json_stack);
783 /***************************************************************************/
784 /* We may want to generate and POST a response to the command list. */
785 /***************************************************************************/
788 evel_command_list_response(post);
791 /***************************************************************************/
792 /* Make sure we're clean on exit. */
793 /***************************************************************************/
794 assert(evel_command_type_value == NULL);
795 assert(evel_measurement_interval_value == NULL);
796 assert(evel_throttle_spec_domain_value == NULL);
797 assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
798 assert(evel_temp_throttle == NULL);
805 /**************************************************************************//**
806 * Copy a copy of an element, in string form.
808 * The caller must manage memory allocated for the copied string.
810 * @param chunk Memory chunk containing the JSON buffer.
811 * @param token The token to copy from.
812 * @return the copy of the element.
813 *****************************************************************************/
814 char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
815 const jsmntok_t * const token)
822 /***************************************************************************/
823 /* Call strdup to copy the string, inserting a temporary \0 for the call. */
824 /***************************************************************************/
825 temp_char = chunk->memory[token->end];
826 chunk->memory[token->end] = '\0';
827 result = strdup(chunk->memory + token->start);
828 assert(result != NULL);
829 chunk->memory[token->end] = temp_char;
836 /**************************************************************************//**
837 * Copy a copy of an element, in string form.
839 * @param json_stack The JSON stack to initialize.
840 * @param chunk The underlying memory chunk used for parsing.
841 *****************************************************************************/
842 void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
843 const MEMORY_CHUNK * const chunk)
845 EVEL_JSON_STACK_ENTRY * entry;
849 json_stack->level = 0;
850 entry = json_stack->entry;
851 entry->json_state = EVEL_JSON_ITEM;
852 entry->json_count = 0;
853 entry->num_required = 1;
854 entry->json_key = NULL;
855 json_stack->chunk = chunk;
860 /**************************************************************************//**
861 * Push a new entry on the stack
863 * @param json_stack The stack.
864 * @param num_required The number of elements required.
865 * @param new_state The state for the new entry.
866 * @return false if we cannot push onto the stack.
867 *****************************************************************************/
868 bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
869 const int num_required,
870 const EVEL_JSON_STATE new_state)
872 EVEL_JSON_STACK_ENTRY * entry;
878 /***************************************************************************/
879 /* Check preconditions. */
880 /***************************************************************************/
881 assert(json_stack != NULL);
882 assert(json_stack->level >= 0);
883 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
884 assert((new_state == EVEL_JSON_ITEM) || (new_state == EVEL_JSON_KEY));
886 /***************************************************************************/
887 /* Check nesting depth, and stop processing if we hit the limit. */
888 /***************************************************************************/
889 if ((json_stack->level + 1) >= EVEL_JSON_STACK_DEPTH)
891 EVEL_ERROR("JSON Nesting is too deep - stop processing");
896 /***************************************************************************/
897 /* Evaluate cases where we recurse and are interested in the contents. */
898 /***************************************************************************/
899 entry = &json_stack->entry[json_stack->level];
900 key = entry->json_key;
902 /***************************************************************************/
903 /* Note that this is the key before we drop a level. */
904 /***************************************************************************/
907 EVEL_DEBUG("Push with key: %s", key);
909 switch (evel_json_command_state)
912 if (strcmp(key, "commandList") == 0)
914 evel_set_command_state(EVEL_JCS_COMMAND_LIST);
918 case EVEL_JCS_COMMAND_LIST_ENTRY:
919 if (strcmp(key, "command") == 0)
922 evel_set_command_state(EVEL_JCS_COMMAND);
926 case EVEL_JCS_COMMAND:
927 if (strcmp(key, "eventDomainThrottleSpecification") == 0)
929 evel_open_throttle_spec();
930 evel_set_command_state(EVEL_JCS_SPEC);
935 if (strcmp(key, "suppressedFieldNames") == 0)
937 evel_set_command_state(EVEL_JCS_FIELD_NAMES);
939 else if (strcmp(key, "suppressedNvPairsList") == 0)
941 evel_set_command_state(EVEL_JCS_PAIRS_LIST);
945 case EVEL_JCS_PAIRS_LIST_ENTRY:
946 if (strcmp(key, "suppressedNvPairNames") == 0)
948 evel_set_command_state(EVEL_JCS_NV_PAIR_NAMES);
952 case EVEL_JCS_FIELD_NAMES:
953 case EVEL_JCS_PAIRS_LIST:
954 case EVEL_JCS_NV_PAIR_NAMES:
956 EVEL_ERROR("Unexpected JSON key %s in state %d",
958 evel_json_command_state);
964 EVEL_DEBUG("Push with no key");
966 /*************************************************************************/
967 /* If we're pushing without a key, then we're in an array. We switch */
968 /* state based on the existing state and stack level. */
969 /*************************************************************************/
970 const int COMMAND_LIST_LEVEL = 2;
971 const int NV_PAIRS_LIST_LEVEL = 6;
973 if ((evel_json_command_state == EVEL_JCS_PAIRS_LIST) &&
974 (json_stack->level == NV_PAIRS_LIST_LEVEL))
976 /***********************************************************************/
977 /* We are entering an object within the "suppressedNvPairsList" array. */
978 /***********************************************************************/
979 evel_open_nv_pairs_list_entry();
980 evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
983 if ((evel_json_command_state == EVEL_JCS_COMMAND_LIST) &&
984 (json_stack->level == COMMAND_LIST_LEVEL))
986 /***********************************************************************/
987 /* We are entering an object within the "commandList" array. */
988 /***********************************************************************/
989 evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
993 /***************************************************************************/
994 /* Push the stack and initialize the entry. */
995 /***************************************************************************/
998 EVEL_DEBUG("Stack Push -> %d", json_stack->level);
999 entry = &json_stack->entry[json_stack->level];
1000 entry->json_count = 0;
1001 entry->num_required = num_required;
1002 entry->json_state = new_state;
1003 entry->json_key = NULL;
1013 /**************************************************************************//**
1014 * Pop any stack entries which have collected the required number of items.
1016 * @param json_stack The stack.
1017 *****************************************************************************/
1018 void evel_stack_pop(EVEL_JSON_STACK * const json_stack)
1020 EVEL_JSON_STACK_ENTRY * entry;
1025 /***************************************************************************/
1026 /* Check preconditions. */
1027 /***************************************************************************/
1028 assert(json_stack != NULL);
1029 assert(json_stack->level >= 0);
1030 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1032 entry = &json_stack->entry[json_stack->level];
1033 while ((json_stack->level > 0) && (entry->json_count == entry->num_required))
1035 key = entry->json_key;
1037 switch (evel_json_command_state)
1039 case EVEL_JCS_COMMAND_LIST:
1040 evel_set_command_state(EVEL_JCS_START);
1043 case EVEL_JCS_COMMAND_LIST_ENTRY:
1044 evel_set_command_state(EVEL_JCS_COMMAND_LIST);
1047 case EVEL_JCS_COMMAND:
1048 evel_close_command();
1049 evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
1053 evel_close_throttle_spec();
1054 evel_set_command_state(EVEL_JCS_COMMAND);
1057 case EVEL_JCS_FIELD_NAMES:
1058 evel_set_command_state(EVEL_JCS_SPEC);
1061 case EVEL_JCS_PAIRS_LIST:
1062 evel_set_command_state(EVEL_JCS_SPEC);
1065 case EVEL_JCS_PAIRS_LIST_ENTRY:
1066 evel_close_nv_pairs_list_entry();
1067 evel_set_command_state(EVEL_JCS_PAIRS_LIST);
1070 case EVEL_JCS_NV_PAIR_NAMES:
1071 evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
1078 /*************************************************************************/
1079 /* Free off any key that was duplicated and stored. */
1080 /*************************************************************************/
1084 entry->json_key = NULL;
1087 /*************************************************************************/
1088 /* We just reached the required number of key-value pairs or items, so */
1089 /* pop the stack. */
1090 /*************************************************************************/
1091 json_stack->level--;
1094 EVEL_DEBUG("Stack Pop -> %d", json_stack->level);
1096 /*************************************************************************/
1097 /* We just completed collection of an ITEM (within an ARRAY) or a VALUE */
1098 /* (within an OBJECT). Either way, we need to count it. */
1099 /*************************************************************************/
1100 entry->json_count++;
1102 /*************************************************************************/
1103 /* If we just completed a VALUE, then we expect the next element to be a */
1104 /* key, if there is a next element. */
1105 /*************************************************************************/
1106 if (entry->json_state == EVEL_JSON_VALUE)
1108 entry->json_state = EVEL_JSON_KEY;
1115 /**************************************************************************//**
1116 * Pop all stack entries, freeing any memory as we go.
1118 * @param json_stack The stack.
1119 *****************************************************************************/
1120 void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack)
1122 EVEL_JSON_STACK_ENTRY * entry;
1126 /***************************************************************************/
1127 /* Check preconditions. */
1128 /***************************************************************************/
1129 assert(json_stack != NULL);
1130 assert(json_stack->level >= 0);
1131 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1133 entry = &json_stack->entry[json_stack->level];
1134 while ((json_stack->level > 0))
1136 /*************************************************************************/
1137 /* Free off any key that was duplicated and stored. */
1138 /*************************************************************************/
1139 if (entry->json_key != NULL)
1141 free(entry->json_key);
1142 entry->json_key = NULL;
1145 /*************************************************************************/
1146 /* We just reached the required number of key-value pairs or items, so */
1147 /* pop the stack. */
1148 /*************************************************************************/
1149 json_stack->level--;
1153 /***************************************************************************/
1154 /* If we hit EVEL_JSON_STACK_DEPTH, we exit the loop and can leave these */
1155 /* values hanging - so clean them up. */
1156 /***************************************************************************/
1157 if (evel_command_type_value != NULL)
1159 free(evel_command_type_value);
1160 evel_command_type_value = NULL;
1162 if (evel_measurement_interval_value != NULL)
1164 free(evel_measurement_interval_value);
1165 evel_measurement_interval_value = NULL;
1167 if (evel_throttle_spec_domain_value != NULL)
1169 free(evel_throttle_spec_domain_value);
1170 evel_throttle_spec_domain_value = NULL;
1172 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1173 if (evel_temp_throttle != NULL)
1175 evel_throttle_free(evel_temp_throttle);
1176 evel_temp_throttle = NULL;
1182 /**************************************************************************//**
1183 * Store a key in the JSON stack.
1185 * We always store the most recent key at each level in the stack.
1187 * @param json_stack The stack.
1188 * @param token The token holding the key.
1189 *****************************************************************************/
1190 void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
1191 const jsmntok_t * const token)
1193 EVEL_JSON_STACK_ENTRY * entry;
1197 /***************************************************************************/
1198 /* Check preconditions. */
1199 /***************************************************************************/
1200 assert(json_stack != NULL);
1201 assert(json_stack->level >= 0);
1202 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1204 /***************************************************************************/
1205 /* Free any previously stored key, replacing it with the new one. */
1206 /***************************************************************************/
1207 entry = &json_stack->entry[json_stack->level];
1208 if (entry->json_key != NULL)
1210 free(entry->json_key);
1212 entry->json_key = evel_stack_strdup(json_stack->chunk, token);
1214 /***************************************************************************/
1215 /* Switch state to collecting the corresponding value. */
1216 /***************************************************************************/
1217 entry->json_state = EVEL_JSON_VALUE;
1219 EVEL_DEBUG("Stored key: %s", entry->json_key);
1223 /**************************************************************************//**
1224 * Store a value in the JSON stack.
1226 * @param json_stack The stack.
1227 * @param token The token holding the value.
1228 *****************************************************************************/
1229 void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
1230 const jsmntok_t * const token)
1232 EVEL_JSON_STACK_ENTRY * entry;
1238 /***************************************************************************/
1239 /* Check preconditions. */
1240 /***************************************************************************/
1241 assert(json_stack != NULL);
1242 assert(json_stack->level >= 0);
1243 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1245 /***************************************************************************/
1246 /* Based on the (key, state), work out whether we're expecting a value, */
1247 /* then store or ignore it as required. */
1248 /***************************************************************************/
1249 entry = &json_stack->entry[json_stack->level];
1250 value = evel_stack_strdup(json_stack->chunk, token);
1252 EVEL_DEBUG("Store value: %s", value);
1254 switch (evel_json_command_state)
1256 case EVEL_JCS_COMMAND:
1257 if (strcmp(entry->json_key, "commandType") == 0)
1259 evel_command_type_value = value;
1262 else if (strcmp(entry->json_key, "measurementInterval") == 0)
1264 evel_measurement_interval_value = value;
1270 if (strcmp(entry->json_key, "eventDomain") == 0)
1272 evel_throttle_spec_domain_value = value;
1277 case EVEL_JCS_PAIRS_LIST_ENTRY:
1278 if (strcmp(entry->json_key, "nvPairFieldName") == 0)
1280 evel_store_nv_pair_field_name(value);
1286 EVEL_DEBUG("Ignoring value in state: %s",
1287 evel_jcs_strings[evel_json_command_state]);
1293 EVEL_DEBUG("Ignored value: %s", value);
1297 /***************************************************************************/
1298 /* Switch state to another key. */
1299 /***************************************************************************/
1300 entry->json_state = EVEL_JSON_KEY;
1302 /***************************************************************************/
1303 /* Count the key-value pair. */
1304 /***************************************************************************/
1305 entry->json_count++;
1310 /**************************************************************************//**
1311 * Store an item in the JSON stack - a string or primitive in an array.
1313 * @param json_stack The stack.
1314 * @param token The token holding the item.
1315 *****************************************************************************/
1316 void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
1317 const jsmntok_t * const token)
1319 EVEL_JSON_STACK_ENTRY * entry;
1325 /***************************************************************************/
1326 /* Check preconditions. */
1327 /***************************************************************************/
1328 assert(json_stack != NULL);
1329 assert(json_stack->level >= 0);
1330 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1332 /***************************************************************************/
1333 /* Based on the state, work out whether we're expecting an item, then */
1334 /* store or ignore it as required. */
1335 /***************************************************************************/
1336 entry = &json_stack->entry[json_stack->level];
1337 item = evel_stack_strdup(json_stack->chunk, token);
1339 EVEL_DEBUG("Store item: %s", item);
1341 switch (evel_json_command_state)
1343 case EVEL_JCS_NV_PAIR_NAMES:
1344 evel_store_nv_pair_name(item);
1348 case EVEL_JCS_FIELD_NAMES:
1349 evel_store_suppressed_field_name(item);
1354 EVEL_DEBUG("Ignoring item in state: %s",
1355 evel_jcs_strings[evel_json_command_state]);
1361 EVEL_DEBUG("Ignored item: %s", item);
1365 /***************************************************************************/
1366 /* We need another item. This is purely defensive. */
1367 /***************************************************************************/
1368 entry->json_state = EVEL_JSON_ITEM;
1370 /***************************************************************************/
1371 /* Count the item. */
1372 /***************************************************************************/
1373 entry->json_count++;
1376 /**************************************************************************//**
1377 * Set the JSON command state to a new value.
1379 * @param new_state The new state to set.
1380 *****************************************************************************/
1381 void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state)
1385 /***************************************************************************/
1386 /* Check preconditions. */
1387 /***************************************************************************/
1388 assert(evel_json_command_state < EVEL_JCS_MAX);
1389 assert(new_state < EVEL_JCS_MAX);
1391 /***************************************************************************/
1392 /* Provide common debug, and set the new state. */
1393 /***************************************************************************/
1394 EVEL_DEBUG("Command State: %s -> %s",
1395 evel_jcs_strings[evel_json_command_state],
1396 evel_jcs_strings[new_state]);
1397 evel_json_command_state = new_state;
1402 /**************************************************************************//**
1403 * Produce debug output from a JSON token.
1405 * @param chunk Memory chunk containing the JSON buffer.
1406 * @param token Token to dump.
1407 *****************************************************************************/
1408 void evel_debug_token(const MEMORY_CHUNK * const chunk,
1409 const jsmntok_t * const token)
1415 /***************************************************************************/
1416 /* Check preconditions. */
1417 /***************************************************************************/
1418 assert(token->type > 0);
1419 assert(token->type < JSON_TOKEN_TYPES);
1421 /***************************************************************************/
1422 /* Log the token, leaving it in the state in which it started. */
1423 /***************************************************************************/
1424 temp_char = chunk->memory[token->end];
1425 chunk->memory[token->end] = '\0';
1426 EVEL_DEBUG("JSON token type: %s", evel_json_token_strings[token->type]);
1427 EVEL_DEBUG("JSON token: %s", chunk->memory + token->start);
1428 chunk->memory[token->end] = temp_char;
1433 /**************************************************************************//**
1434 * Post a response to the commandList.
1436 * @param post Memory chunk in which to post a response.
1437 *****************************************************************************/
1438 void evel_command_list_response(MEMORY_CHUNK * const post)
1444 /***************************************************************************/
1445 /* Check preconditions. */
1446 /***************************************************************************/
1447 assert(post != NULL);
1448 assert(post->memory == NULL);
1450 if (evel_provide_throttling_state)
1452 EVEL_DEBUG("Provide throttling state");
1454 /*************************************************************************/
1455 /* Encode the response, making it printf-able for debug. */
1456 /*************************************************************************/
1457 json_post = malloc(EVEL_MAX_JSON_BODY);
1458 assert(json_post != NULL);
1459 post->size = evel_json_encode_throttle(json_post, EVEL_MAX_JSON_BODY - 1);
1460 post->memory = json_post;
1461 post->memory[post->size] = '\0';
1462 evel_provide_throttling_state = false;
1468 /**************************************************************************//**
1469 * Encode the full throttling specification according to AT&T's schema.
1471 * @param json Pointer to where to store the JSON encoded data.
1472 * @param max_size Size of storage available in json_body.
1473 * @returns Number of bytes actually written.
1474 *****************************************************************************/
1475 int evel_json_encode_throttle(char * const json, const int max_size)
1484 /***************************************************************************/
1485 /* Check preconditions. */
1486 /***************************************************************************/
1487 assert(json != NULL);
1488 assert(max_size > 0);
1490 /***************************************************************************/
1491 /* Work out if we're throttled. */
1492 /***************************************************************************/
1494 for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1496 if (evel_throttle_spec[domain] != NULL)
1502 /***************************************************************************/
1503 /* Encode the response. */
1504 /***************************************************************************/
1506 offset += snprintf(json + offset, max_size - offset,
1507 "{\"eventThrottlingState\": {");
1508 offset += snprintf(json + offset, max_size - offset,
1509 "\"eventThrottlingMode\": \"%s\"",
1510 throttled ? "throttled" : "normal");
1513 offset += snprintf(json + offset, max_size - offset,
1514 ", \"eventDomainThrottleSpecificationList\": [");
1516 domain_added = false;
1517 for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1519 if (evel_throttle_spec[domain] != NULL)
1523 offset += snprintf(json + offset, max_size - offset, ", ");
1526 offset += evel_json_encode_throttle_spec(json + offset,
1529 domain_added = true;
1533 offset += snprintf(json + offset, max_size - offset, "]");
1536 offset += snprintf(json + offset, max_size - offset, "}}");
1543 /**************************************************************************//**
1544 * Encode a throttling specification for a domain.
1546 * @param json Pointer to where to store the JSON encoded data.
1547 * @param max_size Size of storage available in json_body.
1548 * @returns Number of bytes actually written.
1549 *****************************************************************************/
1550 int evel_json_encode_throttle_spec(char * const json,
1552 const EVEL_EVENT_DOMAINS domain)
1555 EVEL_THROTTLE_SPEC * throttle_spec;
1556 DLIST_ITEM * dlist_item;
1559 /***************************************************************************/
1560 /* Check preconditions. */
1561 /***************************************************************************/
1562 assert(domain >= EVEL_DOMAIN_FAULT);
1563 assert(domain < EVEL_MAX_DOMAINS);
1564 assert(evel_throttle_spec[domain] != NULL);
1566 throttle_spec = evel_throttle_spec[domain];
1568 /***************************************************************************/
1569 /* Encode the domain. */
1570 /***************************************************************************/
1572 offset += snprintf(json + offset, max_size - offset,
1574 offset += snprintf(json + offset, max_size - offset,
1575 "\"eventDomain\": \"%s\"",
1576 evel_domain_strings[domain]);
1578 /***************************************************************************/
1579 /* Encode "suppressedFieldNames". */
1580 /***************************************************************************/
1581 dlist_item = dlist_get_first(&throttle_spec->suppressed_field_names);
1582 if (dlist_item != NULL)
1584 offset += snprintf(json + offset, max_size - offset,
1585 ", \"suppressedFieldNames\": [");
1586 while (dlist_item != NULL)
1588 char * suppressed_field = dlist_item->item;
1589 assert(suppressed_field != NULL);
1591 offset += snprintf(json + offset, max_size - offset,
1592 "\"%s\"", suppressed_field);
1593 dlist_item = dlist_get_next(dlist_item);
1594 if (dlist_item != NULL)
1596 offset += snprintf(json + offset, max_size - offset, ", ");
1600 offset += snprintf(json + offset, max_size - offset, "]");
1603 /***************************************************************************/
1604 /* Encode "suppressedNvPairsList". */
1605 /***************************************************************************/
1606 dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
1607 if (dlist_item != NULL)
1609 offset += snprintf(json + offset, max_size - offset,
1610 ", \"suppressedNvPairsList\": [");
1611 while (dlist_item != NULL)
1613 offset += evel_json_encode_nv_pairs(json + offset,
1616 dlist_item = dlist_get_next(dlist_item);
1617 if (dlist_item != NULL)
1619 offset += snprintf(json + offset, max_size - offset, ", ");
1623 offset += snprintf(json + offset, max_size - offset, "]");
1626 offset += snprintf(json + offset, max_size - offset, "}");
1633 /**************************************************************************//**
1634 * Encode a single "suppressedNvPairsListEntry".
1636 * @param json Pointer to where to store the JSON encoded data.
1637 * @param max_size Size of storage available in json_body.
1638 * @returns Number of bytes actually written.
1639 *****************************************************************************/
1640 int evel_json_encode_nv_pairs(char * const json,
1642 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
1644 DLIST_ITEM * dlist_item;
1648 /***************************************************************************/
1649 /* Check preconditions. */
1650 /***************************************************************************/
1651 assert(nv_pairs != NULL);
1652 assert(nv_pairs->nv_pair_field_name != NULL);
1653 assert(!dlist_is_empty(&nv_pairs->suppressed_nv_pair_names));
1655 /***************************************************************************/
1657 /***************************************************************************/
1659 offset += snprintf(json + offset, max_size - offset, "{");
1660 offset += snprintf(json + offset, max_size - offset,
1661 "\"nvPairFieldName\": \"%s\"",
1662 nv_pairs->nv_pair_field_name);
1663 dlist_item = dlist_get_first(&nv_pairs->suppressed_nv_pair_names);
1664 offset += snprintf(json + offset, max_size - offset,
1665 ", \"suppressedNvPairNames\": [");
1666 while (dlist_item != NULL)
1668 name = dlist_item->item;
1669 assert(name != NULL);
1670 offset += snprintf(json + offset, max_size - offset, "\"%s\"", name);
1671 dlist_item = dlist_get_next(dlist_item);
1672 if (dlist_item != NULL)
1674 offset += snprintf(json + offset, max_size - offset, ", ");
1677 offset += snprintf(json + offset, max_size - offset, "]");
1678 offset += snprintf(json + offset, max_size - offset, "}");
1685 /**************************************************************************//**
1686 * Method called when we open a "command" object.
1687 *****************************************************************************/
1688 void evel_open_command()
1692 /***************************************************************************/
1693 /* Make some assertions. */
1694 /***************************************************************************/
1695 assert(evel_command_type_value == NULL);
1696 assert(evel_measurement_interval_value == NULL);
1701 /**************************************************************************//**
1702 * Method called when we close a "command" object.
1703 *****************************************************************************/
1704 void evel_close_command()
1708 /***************************************************************************/
1709 /* If a commandType was provided, fan out and handle it now what we have */
1710 /* fathered all related information. */
1712 /* Note that we handle throttling specification and measurement interval */
1713 /* updates immediately on closing the command (not the list). We could */
1714 /* reject *all* commands in a list if any of them are invalid, but we are */
1715 /* take a best-effort strategy here - any valid-looking command gets */
1716 /* implemented regardless of what follows. */
1717 /***************************************************************************/
1718 if (evel_command_type_value != NULL)
1720 EVEL_DEBUG("Closing command %s", evel_command_type_value);
1722 if (strcmp(evel_command_type_value, "provideThrottlingState") == 0)
1724 evel_provide_throttling_state = true;
1726 else if (strcmp(evel_command_type_value, "throttlingSpecification") == 0)
1728 evel_set_throttling_spec();
1730 else if (strcmp(evel_command_type_value, "measurementIntervalChange") == 0)
1732 evel_set_measurement_interval();
1736 EVEL_ERROR("Ignoring unknown commandType: %s\n",
1737 evel_command_type_value);
1740 /*************************************************************************/
1741 /* Free the captured "commandType" value. */
1742 /*************************************************************************/
1743 free(evel_command_type_value);
1744 evel_command_type_value = NULL;
1747 /***************************************************************************/
1748 /* There could be an unused working throttle spec at this point - if the */
1749 /* "throttlingSpecification" commandType was not provided, or an invalid */
1750 /* domain was provided, or was not provided at all. */
1751 /***************************************************************************/
1752 if (evel_temp_throttle != NULL)
1754 evel_throttle_free(evel_temp_throttle);
1755 evel_temp_throttle = NULL;
1758 /***************************************************************************/
1759 /* Similarly, the domain could be set. */
1760 /***************************************************************************/
1761 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1763 /***************************************************************************/
1764 /* There could be an unused measurement interval value at this point - if */
1765 /* the "measurementIntervalChange" command was not provided. */
1766 /***************************************************************************/
1767 if (evel_measurement_interval_value != NULL)
1769 free(evel_measurement_interval_value);
1770 evel_measurement_interval_value = NULL;
1776 /**************************************************************************//**
1777 * Set the provided throttling specification, when the command closes.
1778 *****************************************************************************/
1779 void evel_set_throttling_spec()
1783 if ((evel_throttle_spec_domain >= 0) &&
1784 (evel_throttle_spec_domain < EVEL_MAX_DOMAINS))
1786 EVEL_DEBUG("Updating throttle spec for domain: %s",
1787 evel_domain_strings[evel_throttle_spec_domain]);
1789 /*************************************************************************/
1790 /* Free off the previous throttle specification for the domain, if there */
1792 /*************************************************************************/
1793 if (evel_throttle_spec[evel_throttle_spec_domain] != NULL)
1795 evel_throttle_free(evel_throttle_spec[evel_throttle_spec_domain]);
1798 /*************************************************************************/
1799 /* Finalize the working throttling spec, if there is one. */
1800 /*************************************************************************/
1801 if (evel_temp_throttle != NULL)
1803 evel_throttle_finalize(evel_temp_throttle);
1806 /*************************************************************************/
1807 /* Replace the throttle specification for the domain with the working */
1808 /* throttle specification. This could be NULL, if an empty throttle */
1809 /* specification has been received for a domain. */
1810 /*************************************************************************/
1811 evel_throttle_spec[evel_throttle_spec_domain] = evel_temp_throttle;
1812 evel_temp_throttle = NULL;
1818 /**************************************************************************//**
1819 * Set the provided measurement interval, when the command closes.
1820 *****************************************************************************/
1821 void evel_set_measurement_interval()
1825 if (evel_measurement_interval_value != NULL)
1827 const long int value = strtol(evel_measurement_interval_value, NULL, 10);
1829 if ((value >= 0) && (value <= INT_MAX))
1831 /***********************************************************************/
1832 /* Lock, update, unlock. */
1833 /***********************************************************************/
1834 EVEL_DEBUG("Updating measurement interval to %d\n", value);
1836 pthread_mutex_lock(&evel_measurement_interval_mutex);
1837 evel_measurement_interval = value;
1838 pthread_mutex_unlock(&evel_measurement_interval_mutex);
1842 EVEL_ERROR("Ignoring invalid measurement interval: %s",
1843 evel_measurement_interval_value);
1850 /**************************************************************************//**
1851 * Method called when we open an "eventDomainThrottleSpecification" object.
1852 *****************************************************************************/
1853 void evel_open_throttle_spec()
1857 /***************************************************************************/
1858 /* Check preconditions. */
1859 /***************************************************************************/
1860 assert(evel_throttle_spec_domain_value == NULL);
1861 assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
1862 assert(evel_temp_throttle == NULL);
1864 /***************************************************************************/
1865 /* Allocate and initialize an ::EVEL_THROTTLE_SPEC in which to hold */
1866 /* captured JSON elements. */
1867 /***************************************************************************/
1868 evel_temp_throttle = malloc(sizeof(EVEL_THROTTLE_SPEC));
1869 assert(evel_temp_throttle != NULL);
1870 dlist_initialize(&evel_temp_throttle->suppressed_field_names);
1871 dlist_initialize(&evel_temp_throttle->suppressed_nv_pairs_list);
1872 evel_temp_throttle->hash_field_names = NULL;
1873 evel_temp_throttle->hash_nv_pairs_list = NULL;
1878 /**************************************************************************//**
1879 * Method called when we close an "eventDomainThrottleSpecification" object.
1880 *****************************************************************************/
1881 void evel_close_throttle_spec()
1885 /***************************************************************************/
1886 /* Decode, free and blank a captured event domain value. */
1887 /***************************************************************************/
1888 if (evel_throttle_spec_domain_value != NULL)
1890 evel_throttle_spec_domain =
1891 evel_decode_domain(evel_throttle_spec_domain_value);
1892 free(evel_throttle_spec_domain_value);
1893 evel_throttle_spec_domain_value = NULL;
1896 /***************************************************************************/
1897 /* Free off an empty working throttle spec, to stop it being used. This */
1898 /* state should be represented by a NULL pointer for the domain. */
1899 /***************************************************************************/
1900 if (evel_temp_throttle != NULL)
1902 if (dlist_is_empty(&evel_temp_throttle->suppressed_field_names) &&
1903 dlist_is_empty(&evel_temp_throttle->suppressed_nv_pairs_list))
1905 free(evel_temp_throttle);
1906 evel_temp_throttle = NULL;
1913 /**************************************************************************//**
1914 * Convert a value for an "eventDomain" into an ::EVEL_EVENT_DOMAINS.
1916 * @param domain_value The domain string value to decode.
1917 * @returns The matching ::EVEL_EVENT_DOMAINS, or ::EVEL_MAX_DOMAINS on error.
1918 *****************************************************************************/
1919 EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value)
1921 EVEL_EVENT_DOMAINS result;
1926 /***************************************************************************/
1927 /* Check preconditions. */
1928 /***************************************************************************/
1929 assert(domain_value != NULL);
1931 result = EVEL_MAX_DOMAINS;
1932 for (ii = EVEL_DOMAIN_FAULT; ii < EVEL_MAX_DOMAINS; ii++)
1934 assert(evel_domain_strings[ii] != NULL);
1935 if (strcmp(evel_domain_strings[ii], domain_value) == 0)
1946 /**************************************************************************//**
1947 * Method called when we open a "suppressedNvPairsListEntry" object.
1948 *****************************************************************************/
1949 void evel_open_nv_pairs_list_entry()
1951 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1955 /***************************************************************************/
1956 /* Check preconditions. */
1957 /***************************************************************************/
1958 assert(evel_temp_throttle != NULL);
1960 /***************************************************************************/
1961 /* Allocate and initialize an ::EVEL_SUPPRESSED_NV_PAIRS, and add it to */
1963 /***************************************************************************/
1964 nv_pairs = malloc(sizeof(EVEL_SUPPRESSED_NV_PAIRS));
1965 assert(nv_pairs != NULL);
1966 nv_pairs->nv_pair_field_name = NULL;
1967 dlist_initialize(&nv_pairs->suppressed_nv_pair_names);
1968 nv_pairs->hash_nv_pair_names = NULL;
1969 dlist_push_last(&evel_temp_throttle->suppressed_nv_pairs_list, nv_pairs);
1974 /**************************************************************************//**
1975 * Method called when we close a "suppressedNvPairsListEntry" object.
1976 *****************************************************************************/
1977 void evel_close_nv_pairs_list_entry()
1979 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1980 EVEL_SUPPRESSED_NV_PAIRS * popped;
1984 /***************************************************************************/
1985 /* Get the latest nv pairs. This also performs the required checks. */
1986 /***************************************************************************/
1987 nv_pairs = evel_get_last_nv_pairs();
1989 /***************************************************************************/
1990 /* For a "suppressedNvPairsListEntry" to have any meaning, we need both */
1991 /* "nvPairFieldName" and "suppressedNvPairNames". If we don't, then pop */
1992 /* and free whatever we just collected. */
1993 /***************************************************************************/
1994 if ((nv_pairs->nv_pair_field_name == NULL) ||
1995 dlist_is_empty(&nv_pairs->suppressed_nv_pair_names))
1997 popped = dlist_pop_last(&evel_temp_throttle->suppressed_nv_pairs_list);
1998 assert(popped == nv_pairs);
1999 evel_throttle_free_nv_pair(popped);
2005 /**************************************************************************//**
2006 * Store an "nvPairFieldName" value in the working throttle spec.
2008 * @param value The value to store.
2009 *****************************************************************************/
2010 void evel_store_nv_pair_field_name(char * const value)
2012 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2016 /***************************************************************************/
2017 /* Get the latest nv pairs. This also performs the required checks. */
2018 /***************************************************************************/
2019 nv_pairs = evel_get_last_nv_pairs();
2021 /***************************************************************************/
2022 /* Store the value. */
2023 /***************************************************************************/
2024 nv_pairs->nv_pair_field_name = value;
2029 /**************************************************************************//**
2030 * Store a "suppressedNvPairNames" item in the working throttle spec.
2032 * @param item The item to store.
2033 *****************************************************************************/
2034 void evel_store_nv_pair_name(char * const item)
2036 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2040 /***************************************************************************/
2041 /* Get the latest nv pairs. This also performs the required checks. */
2042 /***************************************************************************/
2043 nv_pairs = evel_get_last_nv_pairs();
2045 /***************************************************************************/
2046 /* Store the item. */
2047 /***************************************************************************/
2048 dlist_push_last(&nv_pairs->suppressed_nv_pair_names, item);
2053 /**************************************************************************//**
2054 * Store a "suppressedFieldNames" item in the working throttle spec.
2056 * @param item The item to store.
2057 *****************************************************************************/
2058 void evel_store_suppressed_field_name(char * const item)
2062 /***************************************************************************/
2063 /* Check preconditions. */
2064 /***************************************************************************/
2065 assert(evel_temp_throttle != NULL);
2067 /***************************************************************************/
2068 /* Store the item. */
2069 /***************************************************************************/
2070 dlist_push_last(&evel_temp_throttle->suppressed_field_names, item);
2075 /**************************************************************************//**
2076 * Get the last added suppressed nv pairs list entry in the working spec.
2078 * @returns The last entry.
2079 *****************************************************************************/
2080 EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs()
2082 DLIST_ITEM * dlist_item;
2083 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2087 /***************************************************************************/
2088 /* Check preconditions. */
2089 /***************************************************************************/
2090 assert(evel_temp_throttle != NULL);
2092 /***************************************************************************/
2093 /* Get the pair that was added when we opened the list entry. */
2094 /***************************************************************************/
2095 dlist_item = dlist_get_last(&evel_temp_throttle->suppressed_nv_pairs_list);
2096 assert(dlist_item != NULL);
2097 nv_pairs = dlist_item->item;
2098 assert(nv_pairs != NULL);