1 /*************************************************************************//**
3 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
5 * Unless otherwise specified, all software contained herein is
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
17 ****************************************************************************/
19 /**************************************************************************//**
23 * Simple event manager that is responsible for taking events (Heartbeats,
24 * Faults and Measurements) from the ring-buffer and posting them to the API.
26 ****************************************************************************/
36 #include "evel_throttle.h"
38 /*****************************************************************************/
39 /* The Event Throttling State for all domains, indexed by */
40 /* ::EVEL_EVENT_DOMAINS, corresponding to JSON eventDomain. */
42 /* A given domain is in a throttled state if ::evel_throttle_spec is */
44 /*****************************************************************************/
45 static EVEL_THROTTLE_SPEC * evel_throttle_spec[EVEL_MAX_DOMAINS];
47 /*****************************************************************************/
48 /* The current measurement interval. Default: MEASUREMENT_INTERVAL_UKNOWN. */
49 /* Must be protected by evel_measurement_interval_mutex. */
50 /*****************************************************************************/
51 static int evel_measurement_interval;
53 /*****************************************************************************/
54 /* Mutex protecting evel_measurement_interval from contention between an */
55 /* EVEL client reading it, and the EVEL event handler updating it. */
56 /*****************************************************************************/
57 static pthread_mutex_t evel_measurement_interval_mutex;
59 /*****************************************************************************/
60 /* Flag stating that we have received a "provideThrottlingState" command. */
61 /* Set during JSON processing and cleared on sending the throttling state. */
62 /*****************************************************************************/
63 static bool evel_provide_throttling_state;
65 /*****************************************************************************/
66 /* Holder for the "commandType" value during JSON processing. */
67 /*****************************************************************************/
68 static char * evel_command_type_value;
70 /*****************************************************************************/
71 /* Holder for the "measurementInterval" value during JSON processing. */
72 /*****************************************************************************/
73 static char * evel_measurement_interval_value;
75 /*****************************************************************************/
76 /* Holder for the "eventDomain" value during JSON processing. */
77 /*****************************************************************************/
78 static char * evel_throttle_spec_domain_value;
80 /*****************************************************************************/
81 /* Decoded version of ::evel_throttle_spec_domain_value. */
82 /*****************************************************************************/
83 static EVEL_EVENT_DOMAINS evel_throttle_spec_domain;
85 /*****************************************************************************/
86 /* During JSON processing of a single throttling specification, we collect */
87 /* parameters in this working ::EVEL_THROTTLE_SPEC */
88 /*****************************************************************************/
89 static EVEL_THROTTLE_SPEC * evel_temp_throttle;
91 /*****************************************************************************/
92 /* State tracking our progress through the command list */
93 /*****************************************************************************/
94 EVEL_JSON_COMMAND_STATE evel_json_command_state;
96 /*****************************************************************************/
97 /* Debug strings for ::EVEL_JSON_COMMAND_STATE. */
98 /*****************************************************************************/
99 static const char * const evel_jcs_strings[EVEL_JCS_MAX] = {
101 "EVEL_JCS_COMMAND_LIST",
102 "EVEL_JCS_COMMAND_LIST_ENTRY",
105 "EVEL_JCS_FIELD_NAMES",
106 "EVEL_JCS_PAIRS_LIST",
107 "EVEL_JCS_PAIRS_LIST_ENTRY",
108 "EVEL_JCS_NV_PAIR_NAMES"
111 /*****************************************************************************/
112 /* Debug strings for JSON token type. */
113 /*****************************************************************************/
114 #define JSON_TOKEN_TYPES (JSMN_PRIMITIVE + 1)
115 static const char * const evel_json_token_strings[JSON_TOKEN_TYPES] = {
123 /*****************************************************************************/
124 /* Debug strings for JSON domains. */
125 /*****************************************************************************/
126 static const char * evel_domain_strings[EVEL_MAX_DOMAINS] = {
131 "measurementsForVfScaling",
143 /*****************************************************************************/
144 /* Local prototypes. */
145 /*****************************************************************************/
146 static void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec);
147 static struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys);
148 static void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec);
149 static void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
150 static void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
151 const MEMORY_CHUNK * const chunk);
152 static bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
153 const int num_required,
154 const EVEL_JSON_STATE new_state);
155 static void evel_stack_pop(EVEL_JSON_STACK * const json_stack);
156 static void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack);
157 static char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
158 const jsmntok_t * const token);
159 static void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
160 const jsmntok_t * const token);
161 static void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
162 const jsmntok_t * const token);
163 static void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
164 const jsmntok_t * const token);
165 static void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state);
166 static void evel_debug_token(const MEMORY_CHUNK * const chunk,
167 const jsmntok_t * const token);
168 static void evel_command_list_response(MEMORY_CHUNK * const post);
169 static int evel_json_encode_throttle(char * const json, const int max_size);
170 static int evel_json_encode_throttle_spec(char * const json,
172 const EVEL_EVENT_DOMAINS domain);
173 static int evel_json_encode_nv_pairs(char * const json,
175 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
176 static void evel_close_command();
177 static void evel_open_command();
178 static void evel_set_throttling_spec();
179 static void evel_set_measurement_interval();
180 static void evel_open_throttle_spec();
181 static void evel_close_throttle_spec();
182 static EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value);
183 static void evel_open_nv_pairs_list_entry();
184 static void evel_close_nv_pairs_list_entry();
185 static void evel_store_nv_pair_field_name(char * const value);
186 static void evel_store_nv_pair_name(char * const item);
187 static void evel_store_suppressed_field_name(char * const item);
188 static EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs();
190 /**************************************************************************//**
191 * Return the current measurement interval provided by the Event Listener.
193 * @returns The current measurement interval
194 * @retval EVEL_MEASUREMENT_INTERVAL_UKNOWN (0) - interval has not been
196 *****************************************************************************/
197 int evel_get_measurement_interval()
203 /***************************************************************************/
204 /* Lock, read, unlock. */
205 /***************************************************************************/
206 pthread_mutex_lock(&evel_measurement_interval_mutex);
207 result = evel_measurement_interval;
208 pthread_mutex_unlock(&evel_measurement_interval_mutex);
215 /**************************************************************************//**
216 * Return the ::EVEL_THROTTLE_SPEC for a given domain.
218 * @param domain The domain for which to return state.
219 *****************************************************************************/
220 EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain)
222 EVEL_THROTTLE_SPEC * result;
226 /***************************************************************************/
227 /* Check preconditions. */
228 /***************************************************************************/
229 assert(domain < EVEL_MAX_DOMAINS);
231 result = evel_throttle_spec[domain];
238 /**************************************************************************//**
239 * Determine whether a field_name should be suppressed.
241 * @param throttle_spec Throttle specification for the domain being encoded.
242 * @param field_name The field name to encoded or suppress.
243 * @return true if the field_name should be suppressed, false otherwise.
244 *****************************************************************************/
245 bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC * throttle_spec,
246 const char * const field_name)
248 bool suppress = false;
252 /***************************************************************************/
253 /* Check preconditions. */
254 /***************************************************************************/
255 assert(field_name != NULL);
257 /***************************************************************************/
258 /* If the throttle spec and hash table exist, query the field_names table. */
259 /***************************************************************************/
260 if ((throttle_spec != NULL) && (throttle_spec->hash_field_names != NULL))
264 hash_query.key = (char * const) field_name;
265 suppress = (hsearch_r(hash_query,
268 throttle_spec->hash_field_names) != 0);
276 /**************************************************************************//**
277 * Determine whether a name-value pair should be allowed (not suppressed).
279 * @param throttle_spec Throttle specification for the domain being encoded.
280 * @param field_name The field name holding the name-value pairs.
281 * @param name The name of the name-value pair to encoded or suppress.
282 * @return true if the name-value pair should be suppressed, false otherwise.
283 *****************************************************************************/
284 bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC * throttle_spec,
285 const char * const field_name,
286 const char * const name)
288 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
290 bool suppress = false;
294 /***************************************************************************/
295 /* Check preconditions. */
296 /***************************************************************************/
297 assert(field_name != NULL);
298 assert(name != NULL);
300 /***************************************************************************/
301 /* If the throttle spec and hash table exist, query the nv_pairs table. */
302 /***************************************************************************/
303 if ((throttle_spec != NULL) && (throttle_spec->hash_nv_pairs_list != NULL))
307 hash_query.key = (char * const) field_name;
308 hit = (hsearch_r(hash_query,
311 throttle_spec->hash_nv_pairs_list) != 0);
314 nv_pairs = hash_result->data;
318 /***************************************************************************/
319 /* If we got a hit, and the nv_pairs and hash table exist, query the */
320 /* nv_pairs table. */
321 /***************************************************************************/
322 if (hit && (nv_pairs != NULL) && (nv_pairs->hash_nv_pair_names != NULL))
326 hash_query.key = (char * const) name;
327 suppress = (hsearch_r(hash_query,
330 nv_pairs->hash_nv_pair_names) != 0);
338 /**************************************************************************//**
339 * Initialize event throttling to the default state.
341 * Called from ::evel_initialize.
342 *****************************************************************************/
343 void evel_throttle_initialize()
350 for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
352 evel_throttle_spec[ii] = NULL;
355 pthread_rc = pthread_mutex_init(&evel_measurement_interval_mutex, NULL);
356 assert(pthread_rc == 0);
358 evel_measurement_interval = EVEL_MEASUREMENT_INTERVAL_UKNOWN;
363 /**************************************************************************//**
364 * Clean up event throttling.
366 * Called from ::evel_terminate.
367 *****************************************************************************/
368 void evel_throttle_terminate()
375 for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
377 if (evel_throttle_spec[ii] != NULL)
379 evel_throttle_free(evel_throttle_spec[ii]);
380 evel_throttle_spec[ii] = NULL;
384 pthread_rc = pthread_mutex_destroy(&evel_measurement_interval_mutex);
385 assert(pthread_rc == 0);
390 /**************************************************************************//**
391 * Finalize a single ::EVEL_THROTTLE_SPEC.
393 * Now that the specification is collected, build hash tables to simplify the
396 * @param throttle_spec The ::EVEL_THROTTLE_SPEC to finalize.
397 *****************************************************************************/
398 void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec)
401 DLIST_ITEM * dlist_item;
406 /***************************************************************************/
407 /* Check preconditions. */
408 /***************************************************************************/
409 assert(throttle_spec != NULL);
411 /***************************************************************************/
412 /* Populate the hash table for suppressed field names. */
413 /***************************************************************************/
414 throttle_spec->hash_field_names =
415 evel_throttle_hash_create(&throttle_spec->suppressed_field_names);
417 /***************************************************************************/
418 /* Create the hash table for suppressed nv pairs. */
419 /***************************************************************************/
420 nv_pairs_count = dlist_count(&throttle_spec->suppressed_nv_pairs_list);
421 if (nv_pairs_count > 0)
423 throttle_spec->hash_nv_pairs_list = calloc(1, sizeof(struct hsearch_data));
424 assert(throttle_spec->hash_nv_pairs_list != NULL);
426 /*************************************************************************/
427 /* Provide plenty of space in the table - see hcreate_r notes. */
428 /*************************************************************************/
429 if (hcreate_r(nv_pairs_count * 2, throttle_spec->hash_nv_pairs_list) == 0)
431 EVEL_ERROR("Failed to create hash table");
432 free(throttle_spec->hash_nv_pairs_list);
433 throttle_spec->hash_nv_pairs_list = NULL;
437 /***************************************************************************/
438 /* Populate the hash tables under suppressed field names. */
439 /***************************************************************************/
440 dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
441 while (dlist_item != NULL)
443 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs = dlist_item->item;
446 /*************************************************************************/
447 /* Set the key to the string, and the item to the nv_pairs. */
448 /*************************************************************************/
449 assert(nv_pairs != NULL);
450 hash_add.key = nv_pairs->nv_pair_field_name;
451 hash_add.data = nv_pairs;
452 hsearch_r(hash_add, ENTER, &add_result, throttle_spec->hash_nv_pairs_list);
454 /*************************************************************************/
455 /* Create the nv_pair_names hash since we're in here. */
456 /*************************************************************************/
457 nv_pairs->hash_nv_pair_names =
458 evel_throttle_hash_create(&nv_pairs->suppressed_nv_pair_names);
460 dlist_item = dlist_get_next(dlist_item);
466 /**************************************************************************//**
467 * Create and populate a hash table from a DLIST of keys.
469 * @param hash_keys Pointer to a DLIST of hash table keys.
470 * @return Pointer to the created hash-table, or NULL on failure.
471 *****************************************************************************/
472 struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys)
475 struct hsearch_data * hash_table;
480 /***************************************************************************/
481 /* Check preconditions. */
482 /***************************************************************************/
483 assert(hash_keys != NULL);
485 /***************************************************************************/
486 /* Count the keys and if there are any, populate the hash table with them. */
487 /***************************************************************************/
488 key_count = dlist_count(hash_keys);
491 EVEL_DEBUG("Populating table for %d keys", key_count);
493 hash_table = calloc(1, sizeof(struct hsearch_data));
494 assert(hash_table != NULL);
496 /*************************************************************************/
497 /* We need to leave plenty of space in the table - see hcreate_r notes. */
498 /*************************************************************************/
499 if (hcreate_r(key_count * 2, hash_table) != 0)
501 DLIST_ITEM * dlist_item;
502 dlist_item = dlist_get_first(hash_keys);
503 while (dlist_item != NULL)
505 assert(dlist_item->item != NULL);
507 /*********************************************************************/
508 /* Set the key and data to the item, which is a string in this case. */
509 /*********************************************************************/
511 hash_add.key = dlist_item->item;
512 hash_add.data = dlist_item->item;
513 hsearch_r(hash_add, ENTER, &add_result, hash_table);
514 dlist_item = dlist_get_next(dlist_item);
519 EVEL_ERROR("Failed to create hash table");
534 /**************************************************************************//**
535 * Free resources associated with a single ::EVEL_THROTTLE_SPEC.
537 * @param throttle_spec The ::EVEL_THROTTLE_SPEC to free.
538 *****************************************************************************/
539 void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec)
542 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
546 /***************************************************************************/
547 /* Check preconditions. */
548 /***************************************************************************/
549 assert(throttle_spec != NULL);
551 /***************************************************************************/
552 /* Free any hash tables. */
553 /***************************************************************************/
554 if (throttle_spec->hash_field_names != NULL)
556 hdestroy_r(throttle_spec->hash_field_names);
557 free(throttle_spec->hash_field_names);
559 if (throttle_spec->hash_nv_pairs_list != NULL)
561 hdestroy_r(throttle_spec->hash_nv_pairs_list);
562 free(throttle_spec->hash_nv_pairs_list);
565 /***************************************************************************/
566 /* Iterate through the linked lists, freeing memory. */
567 /***************************************************************************/
568 field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
569 while (field_name != NULL)
572 field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
575 nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
576 while (nv_pairs != NULL)
578 evel_throttle_free_nv_pair(nv_pairs);
579 nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
587 /**************************************************************************//**
588 * Free resources associated with a single ::EVEL_SUPPRESSED_NV_PAIR.
590 * @param nv_pair The ::EVEL_SUPPRESSED_NV_PAIR to free.
591 *****************************************************************************/
592 void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
594 char * suppressed_name;
598 /***************************************************************************/
599 /* Check preconditions. */
600 /***************************************************************************/
601 assert(nv_pairs != NULL);
603 /***************************************************************************/
604 /* Free any hash tables. */
605 /***************************************************************************/
606 if (nv_pairs->hash_nv_pair_names != NULL)
608 hdestroy_r(nv_pairs->hash_nv_pair_names);
609 free(nv_pairs->hash_nv_pair_names);
612 /***************************************************************************/
613 /* Iterate through the linked lists, freeing memory. */
614 /***************************************************************************/
615 suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
616 while (suppressed_name != NULL)
618 free(suppressed_name);
619 suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
621 if (nv_pairs->nv_pair_field_name != NULL)
623 free(nv_pairs->nv_pair_field_name);
630 /**************************************************************************//**
631 * Handle a JSON response from the listener, as a list of tokens from JSMN.
633 * @param chunk Memory chunk containing the JSON buffer.
634 * @param json_tokens Array of tokens to handle.
635 * @param num_tokens The number of tokens to handle.
636 * @param post The memory chunk in which to place any resulting POST.
637 * @return true if the command was handled, false otherwise.
638 *****************************************************************************/
639 bool evel_handle_command_list(const MEMORY_CHUNK * const chunk,
640 const jsmntok_t * const json_tokens,
641 const int num_tokens,
642 MEMORY_CHUNK * const post)
644 EVEL_JSON_STACK stack;
645 EVEL_JSON_STACK * json_stack = &stack;
646 EVEL_JSON_STACK_ENTRY * entry;
653 /***************************************************************************/
654 /* Check preconditions. */
655 /***************************************************************************/
656 assert(chunk != NULL);
657 assert(json_tokens != NULL);
658 assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS);
660 /***************************************************************************/
661 /* Collect one top-level item. */
662 /***************************************************************************/
663 evel_init_json_stack(json_stack, chunk);
665 /***************************************************************************/
666 /* Initialize JSON processing variables. */
667 /***************************************************************************/
668 evel_provide_throttling_state = false;
669 evel_command_type_value = NULL;
670 evel_measurement_interval_value = NULL;
671 evel_throttle_spec_domain_value = NULL;
672 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
673 evel_temp_throttle = NULL;
674 evel_json_command_state = EVEL_JCS_START;
676 /***************************************************************************/
677 /* Loop through the tokens, keeping a stack of state representing the */
678 /* nested JSON structure (see json_state). We also track our way through */
679 /* the ::EVEL_JSON_COMMAND_STATE as we go. */
680 /***************************************************************************/
681 while (json_ok && (token_index < num_tokens))
683 const jsmntok_t * const token = &json_tokens[token_index];
687 evel_debug_token(chunk, token);
690 /*************************************************************************/
691 /* We may have popped or pushed, so always re-evaluate the stack entry. */
692 /*************************************************************************/
693 entry = &json_stack->entry[json_stack->level];
698 if ((entry->json_state == EVEL_JSON_ITEM) ||
699 (entry->json_state == EVEL_JSON_VALUE))
701 json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_KEY);
705 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
706 entry->json_state, token_index, token->type);
712 if ((entry->json_state == EVEL_JSON_ITEM) ||
713 (entry->json_state == EVEL_JSON_VALUE))
715 json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_ITEM);
719 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
720 entry->json_state, token_index, token->type);
726 if (entry->json_state == EVEL_JSON_KEY)
728 evel_stack_store_key(json_stack, token);
730 else if (entry->json_state == EVEL_JSON_VALUE)
732 evel_stack_store_value(json_stack, token);
734 else if (entry->json_state == EVEL_JSON_ITEM)
736 evel_stack_store_item(json_stack, token);
740 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
741 entry->json_state, token_index, token->type);
747 if (entry->json_state == EVEL_JSON_VALUE)
749 evel_stack_store_value(json_stack, token);
751 else if (entry->json_state == EVEL_JSON_ITEM)
753 evel_stack_store_item(json_stack, token);
757 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
758 entry->json_state, token_index, token->type);
765 EVEL_ERROR("Unexpected JSON format at token %d (%d)",
766 token_index, token->type);
771 /*************************************************************************/
772 /* Pop the stack if we're counted enough nested items. */
773 /*************************************************************************/
774 evel_stack_pop(json_stack);
779 /***************************************************************************/
780 /* Cleanup the stack - we may have exited without winding it back, if the */
781 /* input was not well formed. */
782 /***************************************************************************/
783 evel_stack_cleanup(json_stack);
785 /***************************************************************************/
786 /* We may want to generate and POST a response to the command list. */
787 /***************************************************************************/
790 evel_command_list_response(post);
793 /***************************************************************************/
794 /* Make sure we're clean on exit. */
795 /***************************************************************************/
796 assert(evel_command_type_value == NULL);
797 assert(evel_measurement_interval_value == NULL);
798 assert(evel_throttle_spec_domain_value == NULL);
799 assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
800 assert(evel_temp_throttle == NULL);
807 /**************************************************************************//**
808 * Copy a copy of an element, in string form.
810 * The caller must manage memory allocated for the copied string.
812 * @param chunk Memory chunk containing the JSON buffer.
813 * @param token The token to copy from.
814 * @return the copy of the element.
815 *****************************************************************************/
816 char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
817 const jsmntok_t * const token)
824 /***************************************************************************/
825 /* Call strdup to copy the string, inserting a temporary \0 for the call. */
826 /***************************************************************************/
827 temp_char = chunk->memory[token->end];
828 chunk->memory[token->end] = '\0';
829 result = strdup(chunk->memory + token->start);
830 assert(result != NULL);
831 chunk->memory[token->end] = temp_char;
838 /**************************************************************************//**
839 * Copy a copy of an element, in string form.
841 * @param json_stack The JSON stack to initialize.
842 * @param chunk The underlying memory chunk used for parsing.
843 *****************************************************************************/
844 void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
845 const MEMORY_CHUNK * const chunk)
847 EVEL_JSON_STACK_ENTRY * entry;
851 json_stack->level = 0;
852 entry = json_stack->entry;
853 entry->json_state = EVEL_JSON_ITEM;
854 entry->json_count = 0;
855 entry->num_required = 1;
856 entry->json_key = NULL;
857 json_stack->chunk = chunk;
862 /**************************************************************************//**
863 * Push a new entry on the stack
865 * @param json_stack The stack.
866 * @param num_required The number of elements required.
867 * @param new_state The state for the new entry.
868 * @return false if we cannot push onto the stack.
869 *****************************************************************************/
870 bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
871 const int num_required,
872 const EVEL_JSON_STATE new_state)
874 EVEL_JSON_STACK_ENTRY * entry;
880 /***************************************************************************/
881 /* Check preconditions. */
882 /***************************************************************************/
883 assert(json_stack != NULL);
884 assert(json_stack->level >= 0);
885 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
886 assert((new_state == EVEL_JSON_ITEM) || (new_state == EVEL_JSON_KEY));
888 /***************************************************************************/
889 /* Check nesting depth, and stop processing if we hit the limit. */
890 /***************************************************************************/
891 if ((json_stack->level + 1) >= EVEL_JSON_STACK_DEPTH)
893 EVEL_ERROR("JSON Nesting is too deep - stop processing");
898 /***************************************************************************/
899 /* Evaluate cases where we recurse and are interested in the contents. */
900 /***************************************************************************/
901 entry = &json_stack->entry[json_stack->level];
902 key = entry->json_key;
904 /***************************************************************************/
905 /* Note that this is the key before we drop a level. */
906 /***************************************************************************/
909 EVEL_DEBUG("Push with key: %s", key);
911 switch (evel_json_command_state)
914 if (strcmp(key, "commandList") == 0)
916 evel_set_command_state(EVEL_JCS_COMMAND_LIST);
920 case EVEL_JCS_COMMAND_LIST_ENTRY:
921 if (strcmp(key, "command") == 0)
924 evel_set_command_state(EVEL_JCS_COMMAND);
928 case EVEL_JCS_COMMAND:
929 if (strcmp(key, "eventDomainThrottleSpecification") == 0)
931 evel_open_throttle_spec();
932 evel_set_command_state(EVEL_JCS_SPEC);
937 if (strcmp(key, "suppressedFieldNames") == 0)
939 evel_set_command_state(EVEL_JCS_FIELD_NAMES);
941 else if (strcmp(key, "suppressedNvPairsList") == 0)
943 evel_set_command_state(EVEL_JCS_PAIRS_LIST);
947 case EVEL_JCS_PAIRS_LIST_ENTRY:
948 if (strcmp(key, "suppressedNvPairNames") == 0)
950 evel_set_command_state(EVEL_JCS_NV_PAIR_NAMES);
954 case EVEL_JCS_FIELD_NAMES:
955 case EVEL_JCS_PAIRS_LIST:
956 case EVEL_JCS_NV_PAIR_NAMES:
958 EVEL_ERROR("Unexpected JSON key %s in state %d",
960 evel_json_command_state);
966 EVEL_DEBUG("Push with no key");
968 /*************************************************************************/
969 /* If we're pushing without a key, then we're in an array. We switch */
970 /* state based on the existing state and stack level. */
971 /*************************************************************************/
972 const int COMMAND_LIST_LEVEL = 2;
973 const int NV_PAIRS_LIST_LEVEL = 6;
975 if ((evel_json_command_state == EVEL_JCS_PAIRS_LIST) &&
976 (json_stack->level == NV_PAIRS_LIST_LEVEL))
978 /***********************************************************************/
979 /* We are entering an object within the "suppressedNvPairsList" array. */
980 /***********************************************************************/
981 evel_open_nv_pairs_list_entry();
982 evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
985 if ((evel_json_command_state == EVEL_JCS_COMMAND_LIST) &&
986 (json_stack->level == COMMAND_LIST_LEVEL))
988 /***********************************************************************/
989 /* We are entering an object within the "commandList" array. */
990 /***********************************************************************/
991 evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
995 /***************************************************************************/
996 /* Push the stack and initialize the entry. */
997 /***************************************************************************/
1000 EVEL_DEBUG("Stack Push -> %d", json_stack->level);
1001 entry = &json_stack->entry[json_stack->level];
1002 entry->json_count = 0;
1003 entry->num_required = num_required;
1004 entry->json_state = new_state;
1005 entry->json_key = NULL;
1015 /**************************************************************************//**
1016 * Pop any stack entries which have collected the required number of items.
1018 * @param json_stack The stack.
1019 *****************************************************************************/
1020 void evel_stack_pop(EVEL_JSON_STACK * const json_stack)
1022 EVEL_JSON_STACK_ENTRY * entry;
1027 /***************************************************************************/
1028 /* Check preconditions. */
1029 /***************************************************************************/
1030 assert(json_stack != NULL);
1031 assert(json_stack->level >= 0);
1032 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1034 entry = &json_stack->entry[json_stack->level];
1035 while ((json_stack->level > 0) && (entry->json_count == entry->num_required))
1037 key = entry->json_key;
1039 switch (evel_json_command_state)
1041 case EVEL_JCS_COMMAND_LIST:
1042 evel_set_command_state(EVEL_JCS_START);
1045 case EVEL_JCS_COMMAND_LIST_ENTRY:
1046 evel_set_command_state(EVEL_JCS_COMMAND_LIST);
1049 case EVEL_JCS_COMMAND:
1050 evel_close_command();
1051 evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
1055 evel_close_throttle_spec();
1056 evel_set_command_state(EVEL_JCS_COMMAND);
1059 case EVEL_JCS_FIELD_NAMES:
1060 evel_set_command_state(EVEL_JCS_SPEC);
1063 case EVEL_JCS_PAIRS_LIST:
1064 evel_set_command_state(EVEL_JCS_SPEC);
1067 case EVEL_JCS_PAIRS_LIST_ENTRY:
1068 evel_close_nv_pairs_list_entry();
1069 evel_set_command_state(EVEL_JCS_PAIRS_LIST);
1072 case EVEL_JCS_NV_PAIR_NAMES:
1073 evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
1080 /*************************************************************************/
1081 /* Free off any key that was duplicated and stored. */
1082 /*************************************************************************/
1086 entry->json_key = NULL;
1089 /*************************************************************************/
1090 /* We just reached the required number of key-value pairs or items, so */
1091 /* pop the stack. */
1092 /*************************************************************************/
1093 json_stack->level--;
1096 EVEL_DEBUG("Stack Pop -> %d", json_stack->level);
1098 /*************************************************************************/
1099 /* We just completed collection of an ITEM (within an ARRAY) or a VALUE */
1100 /* (within an OBJECT). Either way, we need to count it. */
1101 /*************************************************************************/
1102 entry->json_count++;
1104 /*************************************************************************/
1105 /* If we just completed a VALUE, then we expect the next element to be a */
1106 /* key, if there is a next element. */
1107 /*************************************************************************/
1108 if (entry->json_state == EVEL_JSON_VALUE)
1110 entry->json_state = EVEL_JSON_KEY;
1117 /**************************************************************************//**
1118 * Pop all stack entries, freeing any memory as we go.
1120 * @param json_stack The stack.
1121 *****************************************************************************/
1122 void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack)
1124 EVEL_JSON_STACK_ENTRY * entry;
1128 /***************************************************************************/
1129 /* Check preconditions. */
1130 /***************************************************************************/
1131 assert(json_stack != NULL);
1132 assert(json_stack->level >= 0);
1133 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1135 entry = &json_stack->entry[json_stack->level];
1136 while ((json_stack->level > 0))
1138 /*************************************************************************/
1139 /* Free off any key that was duplicated and stored. */
1140 /*************************************************************************/
1141 if (entry->json_key != NULL)
1143 free(entry->json_key);
1144 entry->json_key = NULL;
1147 /*************************************************************************/
1148 /* We just reached the required number of key-value pairs or items, so */
1149 /* pop the stack. */
1150 /*************************************************************************/
1151 json_stack->level--;
1155 /***************************************************************************/
1156 /* If we hit EVEL_JSON_STACK_DEPTH, we exit the loop and can leave these */
1157 /* values hanging - so clean them up. */
1158 /***************************************************************************/
1159 if (evel_command_type_value != NULL)
1161 free(evel_command_type_value);
1162 evel_command_type_value = NULL;
1164 if (evel_measurement_interval_value != NULL)
1166 free(evel_measurement_interval_value);
1167 evel_measurement_interval_value = NULL;
1169 if (evel_throttle_spec_domain_value != NULL)
1171 free(evel_throttle_spec_domain_value);
1172 evel_throttle_spec_domain_value = NULL;
1174 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1175 if (evel_temp_throttle != NULL)
1177 evel_throttle_free(evel_temp_throttle);
1178 evel_temp_throttle = NULL;
1184 /**************************************************************************//**
1185 * Store a key in the JSON stack.
1187 * We always store the most recent key at each level in the stack.
1189 * @param json_stack The stack.
1190 * @param token The token holding the key.
1191 *****************************************************************************/
1192 void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
1193 const jsmntok_t * const token)
1195 EVEL_JSON_STACK_ENTRY * entry;
1199 /***************************************************************************/
1200 /* Check preconditions. */
1201 /***************************************************************************/
1202 assert(json_stack != NULL);
1203 assert(json_stack->level >= 0);
1204 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1206 /***************************************************************************/
1207 /* Free any previously stored key, replacing it with the new one. */
1208 /***************************************************************************/
1209 entry = &json_stack->entry[json_stack->level];
1210 if (entry->json_key != NULL)
1212 free(entry->json_key);
1214 entry->json_key = evel_stack_strdup(json_stack->chunk, token);
1216 /***************************************************************************/
1217 /* Switch state to collecting the corresponding value. */
1218 /***************************************************************************/
1219 entry->json_state = EVEL_JSON_VALUE;
1221 EVEL_DEBUG("Stored key: %s", entry->json_key);
1225 /**************************************************************************//**
1226 * Store a value in the JSON stack.
1228 * @param json_stack The stack.
1229 * @param token The token holding the value.
1230 *****************************************************************************/
1231 void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
1232 const jsmntok_t * const token)
1234 EVEL_JSON_STACK_ENTRY * entry;
1240 /***************************************************************************/
1241 /* Check preconditions. */
1242 /***************************************************************************/
1243 assert(json_stack != NULL);
1244 assert(json_stack->level >= 0);
1245 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1247 /***************************************************************************/
1248 /* Based on the (key, state), work out whether we're expecting a value, */
1249 /* then store or ignore it as required. */
1250 /***************************************************************************/
1251 entry = &json_stack->entry[json_stack->level];
1252 value = evel_stack_strdup(json_stack->chunk, token);
1254 EVEL_DEBUG("Store value: %s", value);
1256 switch (evel_json_command_state)
1258 case EVEL_JCS_COMMAND:
1259 if (strcmp(entry->json_key, "commandType") == 0)
1261 evel_command_type_value = value;
1264 else if (strcmp(entry->json_key, "measurementInterval") == 0)
1266 evel_measurement_interval_value = value;
1272 if (strcmp(entry->json_key, "eventDomain") == 0)
1274 evel_throttle_spec_domain_value = value;
1279 case EVEL_JCS_PAIRS_LIST_ENTRY:
1280 if (strcmp(entry->json_key, "nvPairFieldName") == 0)
1282 evel_store_nv_pair_field_name(value);
1288 EVEL_DEBUG("Ignoring value in state: %s",
1289 evel_jcs_strings[evel_json_command_state]);
1295 EVEL_DEBUG("Ignored value: %s", value);
1299 /***************************************************************************/
1300 /* Switch state to another key. */
1301 /***************************************************************************/
1302 entry->json_state = EVEL_JSON_KEY;
1304 /***************************************************************************/
1305 /* Count the key-value pair. */
1306 /***************************************************************************/
1307 entry->json_count++;
1312 /**************************************************************************//**
1313 * Store an item in the JSON stack - a string or primitive in an array.
1315 * @param json_stack The stack.
1316 * @param token The token holding the item.
1317 *****************************************************************************/
1318 void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
1319 const jsmntok_t * const token)
1321 EVEL_JSON_STACK_ENTRY * entry;
1327 /***************************************************************************/
1328 /* Check preconditions. */
1329 /***************************************************************************/
1330 assert(json_stack != NULL);
1331 assert(json_stack->level >= 0);
1332 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1334 /***************************************************************************/
1335 /* Based on the state, work out whether we're expecting an item, then */
1336 /* store or ignore it as required. */
1337 /***************************************************************************/
1338 entry = &json_stack->entry[json_stack->level];
1339 item = evel_stack_strdup(json_stack->chunk, token);
1341 EVEL_DEBUG("Store item: %s", item);
1343 switch (evel_json_command_state)
1345 case EVEL_JCS_NV_PAIR_NAMES:
1346 evel_store_nv_pair_name(item);
1350 case EVEL_JCS_FIELD_NAMES:
1351 evel_store_suppressed_field_name(item);
1356 EVEL_DEBUG("Ignoring item in state: %s",
1357 evel_jcs_strings[evel_json_command_state]);
1363 EVEL_DEBUG("Ignored item: %s", item);
1367 /***************************************************************************/
1368 /* We need another item. This is purely defensive. */
1369 /***************************************************************************/
1370 entry->json_state = EVEL_JSON_ITEM;
1372 /***************************************************************************/
1373 /* Count the item. */
1374 /***************************************************************************/
1375 entry->json_count++;
1378 /**************************************************************************//**
1379 * Set the JSON command state to a new value.
1381 * @param new_state The new state to set.
1382 *****************************************************************************/
1383 void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state)
1387 /***************************************************************************/
1388 /* Check preconditions. */
1389 /***************************************************************************/
1390 assert(evel_json_command_state < EVEL_JCS_MAX);
1391 assert(new_state < EVEL_JCS_MAX);
1393 /***************************************************************************/
1394 /* Provide common debug, and set the new state. */
1395 /***************************************************************************/
1396 EVEL_DEBUG("Command State: %s -> %s",
1397 evel_jcs_strings[evel_json_command_state],
1398 evel_jcs_strings[new_state]);
1399 evel_json_command_state = new_state;
1404 /**************************************************************************//**
1405 * Produce debug output from a JSON token.
1407 * @param chunk Memory chunk containing the JSON buffer.
1408 * @param token Token to dump.
1409 *****************************************************************************/
1410 void evel_debug_token(const MEMORY_CHUNK * const chunk,
1411 const jsmntok_t * const token)
1417 /***************************************************************************/
1418 /* Check preconditions. */
1419 /***************************************************************************/
1420 assert(token->type > 0);
1421 assert(token->type < JSON_TOKEN_TYPES);
1423 /***************************************************************************/
1424 /* Log the token, leaving it in the state in which it started. */
1425 /***************************************************************************/
1426 temp_char = chunk->memory[token->end];
1427 chunk->memory[token->end] = '\0';
1428 EVEL_DEBUG("JSON token type: %s", evel_json_token_strings[token->type]);
1429 EVEL_DEBUG("JSON token: %s", chunk->memory + token->start);
1430 chunk->memory[token->end] = temp_char;
1435 /**************************************************************************//**
1436 * Post a response to the commandList.
1438 * @param post Memory chunk in which to post a response.
1439 *****************************************************************************/
1440 void evel_command_list_response(MEMORY_CHUNK * const post)
1446 /***************************************************************************/
1447 /* Check preconditions. */
1448 /***************************************************************************/
1449 assert(post != NULL);
1450 assert(post->memory == NULL);
1452 if (evel_provide_throttling_state)
1454 EVEL_DEBUG("Provide throttling state");
1456 /*************************************************************************/
1457 /* Encode the response, making it printf-able for debug. */
1458 /*************************************************************************/
1459 json_post = malloc(EVEL_MAX_JSON_BODY);
1460 assert(json_post != NULL);
1461 post->size = evel_json_encode_throttle(json_post, EVEL_MAX_JSON_BODY - 1);
1462 post->memory = json_post;
1463 post->memory[post->size] = '\0';
1464 evel_provide_throttling_state = false;
1470 /**************************************************************************//**
1471 * Encode the full throttling specification according to AT&T's schema.
1473 * @param json Pointer to where to store the JSON encoded data.
1474 * @param max_size Size of storage available in json_body.
1475 * @returns Number of bytes actually written.
1476 *****************************************************************************/
1477 int evel_json_encode_throttle(char * const json, const int max_size)
1486 /***************************************************************************/
1487 /* Check preconditions. */
1488 /***************************************************************************/
1489 assert(json != NULL);
1490 assert(max_size > 0);
1492 /***************************************************************************/
1493 /* Work out if we're throttled. */
1494 /***************************************************************************/
1496 for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1498 if (evel_throttle_spec[domain] != NULL)
1504 /***************************************************************************/
1505 /* Encode the response. */
1506 /***************************************************************************/
1508 offset += snprintf(json + offset, max_size - offset,
1509 "{\"eventThrottlingState\": {");
1510 offset += snprintf(json + offset, max_size - offset,
1511 "\"eventThrottlingMode\": \"%s\"",
1512 throttled ? "throttled" : "normal");
1515 offset += snprintf(json + offset, max_size - offset,
1516 ", \"eventDomainThrottleSpecificationList\": [");
1518 domain_added = false;
1519 for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1521 if (evel_throttle_spec[domain] != NULL)
1525 offset += snprintf(json + offset, max_size - offset, ", ");
1528 offset += evel_json_encode_throttle_spec(json + offset,
1531 domain_added = true;
1535 offset += snprintf(json + offset, max_size - offset, "]");
1538 offset += snprintf(json + offset, max_size - offset, "}}");
1545 /**************************************************************************//**
1546 * Encode a throttling specification for a domain.
1548 * @param json Pointer to where to store the JSON encoded data.
1549 * @param max_size Size of storage available in json_body.
1550 * @returns Number of bytes actually written.
1551 *****************************************************************************/
1552 int evel_json_encode_throttle_spec(char * const json,
1554 const EVEL_EVENT_DOMAINS domain)
1557 EVEL_THROTTLE_SPEC * throttle_spec;
1558 DLIST_ITEM * dlist_item;
1561 /***************************************************************************/
1562 /* Check preconditions. */
1563 /***************************************************************************/
1564 assert(domain >= EVEL_DOMAIN_FAULT);
1565 assert(domain < EVEL_MAX_DOMAINS);
1566 assert(evel_throttle_spec[domain] != NULL);
1568 throttle_spec = evel_throttle_spec[domain];
1570 /***************************************************************************/
1571 /* Encode the domain. */
1572 /***************************************************************************/
1574 offset += snprintf(json + offset, max_size - offset,
1576 offset += snprintf(json + offset, max_size - offset,
1577 "\"eventDomain\": \"%s\"",
1578 evel_domain_strings[domain]);
1580 /***************************************************************************/
1581 /* Encode "suppressedFieldNames". */
1582 /***************************************************************************/
1583 dlist_item = dlist_get_first(&throttle_spec->suppressed_field_names);
1584 if (dlist_item != NULL)
1586 offset += snprintf(json + offset, max_size - offset,
1587 ", \"suppressedFieldNames\": [");
1588 while (dlist_item != NULL)
1590 char * suppressed_field = dlist_item->item;
1591 assert(suppressed_field != NULL);
1593 offset += snprintf(json + offset, max_size - offset,
1594 "\"%s\"", suppressed_field);
1595 dlist_item = dlist_get_next(dlist_item);
1596 if (dlist_item != NULL)
1598 offset += snprintf(json + offset, max_size - offset, ", ");
1602 offset += snprintf(json + offset, max_size - offset, "]");
1605 /***************************************************************************/
1606 /* Encode "suppressedNvPairsList". */
1607 /***************************************************************************/
1608 dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
1609 if (dlist_item != NULL)
1611 offset += snprintf(json + offset, max_size - offset,
1612 ", \"suppressedNvPairsList\": [");
1613 while (dlist_item != NULL)
1615 offset += evel_json_encode_nv_pairs(json + offset,
1618 dlist_item = dlist_get_next(dlist_item);
1619 if (dlist_item != NULL)
1621 offset += snprintf(json + offset, max_size - offset, ", ");
1625 offset += snprintf(json + offset, max_size - offset, "]");
1628 offset += snprintf(json + offset, max_size - offset, "}");
1635 /**************************************************************************//**
1636 * Encode a single "suppressedNvPairsListEntry".
1638 * @param json Pointer to where to store the JSON encoded data.
1639 * @param max_size Size of storage available in json_body.
1640 * @returns Number of bytes actually written.
1641 *****************************************************************************/
1642 int evel_json_encode_nv_pairs(char * const json,
1644 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
1646 DLIST_ITEM * dlist_item;
1650 /***************************************************************************/
1651 /* Check preconditions. */
1652 /***************************************************************************/
1653 assert(nv_pairs != NULL);
1654 assert(nv_pairs->nv_pair_field_name != NULL);
1655 assert(!dlist_is_empty(&nv_pairs->suppressed_nv_pair_names));
1657 /***************************************************************************/
1659 /***************************************************************************/
1661 offset += snprintf(json + offset, max_size - offset, "{");
1662 offset += snprintf(json + offset, max_size - offset,
1663 "\"nvPairFieldName\": \"%s\"",
1664 nv_pairs->nv_pair_field_name);
1665 dlist_item = dlist_get_first(&nv_pairs->suppressed_nv_pair_names);
1666 offset += snprintf(json + offset, max_size - offset,
1667 ", \"suppressedNvPairNames\": [");
1668 while (dlist_item != NULL)
1670 name = dlist_item->item;
1671 assert(name != NULL);
1672 offset += snprintf(json + offset, max_size - offset, "\"%s\"", name);
1673 dlist_item = dlist_get_next(dlist_item);
1674 if (dlist_item != NULL)
1676 offset += snprintf(json + offset, max_size - offset, ", ");
1679 offset += snprintf(json + offset, max_size - offset, "]");
1680 offset += snprintf(json + offset, max_size - offset, "}");
1687 /**************************************************************************//**
1688 * Method called when we open a "command" object.
1689 *****************************************************************************/
1690 void evel_open_command()
1694 /***************************************************************************/
1695 /* Make some assertions. */
1696 /***************************************************************************/
1697 assert(evel_command_type_value == NULL);
1698 assert(evel_measurement_interval_value == NULL);
1703 /**************************************************************************//**
1704 * Method called when we close a "command" object.
1705 *****************************************************************************/
1706 void evel_close_command()
1710 /***************************************************************************/
1711 /* If a commandType was provided, fan out and handle it now what we have */
1712 /* fathered all related information. */
1714 /* Note that we handle throttling specification and measurement interval */
1715 /* updates immediately on closing the command (not the list). We could */
1716 /* reject *all* commands in a list if any of them are invalid, but we are */
1717 /* take a best-effort strategy here - any valid-looking command gets */
1718 /* implemented regardless of what follows. */
1719 /***************************************************************************/
1720 if (evel_command_type_value != NULL)
1722 EVEL_DEBUG("Closing command %s", evel_command_type_value);
1724 if (strcmp(evel_command_type_value, "provideThrottlingState") == 0)
1726 evel_provide_throttling_state = true;
1728 else if (strcmp(evel_command_type_value, "throttlingSpecification") == 0)
1730 evel_set_throttling_spec();
1732 else if (strcmp(evel_command_type_value, "measurementIntervalChange") == 0)
1734 evel_set_measurement_interval();
1738 EVEL_ERROR("Ignoring unknown commandType: %s\n",
1739 evel_command_type_value);
1742 /*************************************************************************/
1743 /* Free the captured "commandType" value. */
1744 /*************************************************************************/
1745 free(evel_command_type_value);
1746 evel_command_type_value = NULL;
1749 /***************************************************************************/
1750 /* There could be an unused working throttle spec at this point - if the */
1751 /* "throttlingSpecification" commandType was not provided, or an invalid */
1752 /* domain was provided, or was not provided at all. */
1753 /***************************************************************************/
1754 if (evel_temp_throttle != NULL)
1756 evel_throttle_free(evel_temp_throttle);
1757 evel_temp_throttle = NULL;
1760 /***************************************************************************/
1761 /* Similarly, the domain could be set. */
1762 /***************************************************************************/
1763 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1765 /***************************************************************************/
1766 /* There could be an unused measurement interval value at this point - if */
1767 /* the "measurementIntervalChange" command was not provided. */
1768 /***************************************************************************/
1769 if (evel_measurement_interval_value != NULL)
1771 free(evel_measurement_interval_value);
1772 evel_measurement_interval_value = NULL;
1778 /**************************************************************************//**
1779 * Set the provided throttling specification, when the command closes.
1780 *****************************************************************************/
1781 void evel_set_throttling_spec()
1785 if ((evel_throttle_spec_domain >= 0) &&
1786 (evel_throttle_spec_domain < EVEL_MAX_DOMAINS))
1788 EVEL_DEBUG("Updating throttle spec for domain: %s",
1789 evel_domain_strings[evel_throttle_spec_domain]);
1791 /*************************************************************************/
1792 /* Free off the previous throttle specification for the domain, if there */
1794 /*************************************************************************/
1795 if (evel_throttle_spec[evel_throttle_spec_domain] != NULL)
1797 evel_throttle_free(evel_throttle_spec[evel_throttle_spec_domain]);
1800 /*************************************************************************/
1801 /* Finalize the working throttling spec, if there is one. */
1802 /*************************************************************************/
1803 if (evel_temp_throttle != NULL)
1805 evel_throttle_finalize(evel_temp_throttle);
1808 /*************************************************************************/
1809 /* Replace the throttle specification for the domain with the working */
1810 /* throttle specification. This could be NULL, if an empty throttle */
1811 /* specification has been received for a domain. */
1812 /*************************************************************************/
1813 evel_throttle_spec[evel_throttle_spec_domain] = evel_temp_throttle;
1814 evel_temp_throttle = NULL;
1820 /**************************************************************************//**
1821 * Set the provided measurement interval, when the command closes.
1822 *****************************************************************************/
1823 void evel_set_measurement_interval()
1827 if (evel_measurement_interval_value != NULL)
1829 const long int value = strtol(evel_measurement_interval_value, NULL, 10);
1831 if ((value >= 0) && (value <= INT_MAX))
1833 /***********************************************************************/
1834 /* Lock, update, unlock. */
1835 /***********************************************************************/
1836 EVEL_DEBUG("Updating measurement interval to %d\n", value);
1838 pthread_mutex_lock(&evel_measurement_interval_mutex);
1839 evel_measurement_interval = value;
1840 pthread_mutex_unlock(&evel_measurement_interval_mutex);
1844 EVEL_ERROR("Ignoring invalid measurement interval: %s",
1845 evel_measurement_interval_value);
1852 /**************************************************************************//**
1853 * Method called when we open an "eventDomainThrottleSpecification" object.
1854 *****************************************************************************/
1855 void evel_open_throttle_spec()
1859 /***************************************************************************/
1860 /* Check preconditions. */
1861 /***************************************************************************/
1862 assert(evel_throttle_spec_domain_value == NULL);
1863 assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
1864 assert(evel_temp_throttle == NULL);
1866 /***************************************************************************/
1867 /* Allocate and initialize an ::EVEL_THROTTLE_SPEC in which to hold */
1868 /* captured JSON elements. */
1869 /***************************************************************************/
1870 evel_temp_throttle = malloc(sizeof(EVEL_THROTTLE_SPEC));
1871 assert(evel_temp_throttle != NULL);
1872 dlist_initialize(&evel_temp_throttle->suppressed_field_names);
1873 dlist_initialize(&evel_temp_throttle->suppressed_nv_pairs_list);
1874 evel_temp_throttle->hash_field_names = NULL;
1875 evel_temp_throttle->hash_nv_pairs_list = NULL;
1880 /**************************************************************************//**
1881 * Method called when we close an "eventDomainThrottleSpecification" object.
1882 *****************************************************************************/
1883 void evel_close_throttle_spec()
1887 /***************************************************************************/
1888 /* Decode, free and blank a captured event domain value. */
1889 /***************************************************************************/
1890 if (evel_throttle_spec_domain_value != NULL)
1892 evel_throttle_spec_domain =
1893 evel_decode_domain(evel_throttle_spec_domain_value);
1894 free(evel_throttle_spec_domain_value);
1895 evel_throttle_spec_domain_value = NULL;
1898 /***************************************************************************/
1899 /* Free off an empty working throttle spec, to stop it being used. This */
1900 /* state should be represented by a NULL pointer for the domain. */
1901 /***************************************************************************/
1902 if (evel_temp_throttle != NULL)
1904 if (dlist_is_empty(&evel_temp_throttle->suppressed_field_names) &&
1905 dlist_is_empty(&evel_temp_throttle->suppressed_nv_pairs_list))
1907 free(evel_temp_throttle);
1908 evel_temp_throttle = NULL;
1915 /**************************************************************************//**
1916 * Convert a value for an "eventDomain" into an ::EVEL_EVENT_DOMAINS.
1918 * @param domain_value The domain string value to decode.
1919 * @returns The matching ::EVEL_EVENT_DOMAINS, or ::EVEL_MAX_DOMAINS on error.
1920 *****************************************************************************/
1921 EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value)
1923 EVEL_EVENT_DOMAINS result;
1928 /***************************************************************************/
1929 /* Check preconditions. */
1930 /***************************************************************************/
1931 assert(domain_value != NULL);
1933 result = EVEL_MAX_DOMAINS;
1934 for (ii = EVEL_DOMAIN_FAULT; ii < EVEL_MAX_DOMAINS; ii++)
1936 assert(evel_domain_strings[ii] != NULL);
1937 if (strcmp(evel_domain_strings[ii], domain_value) == 0)
1948 /**************************************************************************//**
1949 * Method called when we open a "suppressedNvPairsListEntry" object.
1950 *****************************************************************************/
1951 void evel_open_nv_pairs_list_entry()
1953 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1957 /***************************************************************************/
1958 /* Check preconditions. */
1959 /***************************************************************************/
1960 assert(evel_temp_throttle != NULL);
1962 /***************************************************************************/
1963 /* Allocate and initialize an ::EVEL_SUPPRESSED_NV_PAIRS, and add it to */
1965 /***************************************************************************/
1966 nv_pairs = malloc(sizeof(EVEL_SUPPRESSED_NV_PAIRS));
1967 assert(nv_pairs != NULL);
1968 nv_pairs->nv_pair_field_name = NULL;
1969 dlist_initialize(&nv_pairs->suppressed_nv_pair_names);
1970 nv_pairs->hash_nv_pair_names = NULL;
1971 dlist_push_last(&evel_temp_throttle->suppressed_nv_pairs_list, nv_pairs);
1976 /**************************************************************************//**
1977 * Method called when we close a "suppressedNvPairsListEntry" object.
1978 *****************************************************************************/
1979 void evel_close_nv_pairs_list_entry()
1981 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1982 EVEL_SUPPRESSED_NV_PAIRS * popped;
1986 /***************************************************************************/
1987 /* Get the latest nv pairs. This also performs the required checks. */
1988 /***************************************************************************/
1989 nv_pairs = evel_get_last_nv_pairs();
1991 /***************************************************************************/
1992 /* For a "suppressedNvPairsListEntry" to have any meaning, we need both */
1993 /* "nvPairFieldName" and "suppressedNvPairNames". If we don't, then pop */
1994 /* and free whatever we just collected. */
1995 /***************************************************************************/
1996 if ((nv_pairs->nv_pair_field_name == NULL) ||
1997 dlist_is_empty(&nv_pairs->suppressed_nv_pair_names))
1999 popped = dlist_pop_last(&evel_temp_throttle->suppressed_nv_pairs_list);
2000 assert(popped == nv_pairs);
2001 evel_throttle_free_nv_pair(popped);
2007 /**************************************************************************//**
2008 * Store an "nvPairFieldName" value in the working throttle spec.
2010 * @param value The value to store.
2011 *****************************************************************************/
2012 void evel_store_nv_pair_field_name(char * const value)
2014 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2018 /***************************************************************************/
2019 /* Get the latest nv pairs. This also performs the required checks. */
2020 /***************************************************************************/
2021 nv_pairs = evel_get_last_nv_pairs();
2023 /***************************************************************************/
2024 /* Store the value. */
2025 /***************************************************************************/
2026 nv_pairs->nv_pair_field_name = value;
2031 /**************************************************************************//**
2032 * Store a "suppressedNvPairNames" item in the working throttle spec.
2034 * @param item The item to store.
2035 *****************************************************************************/
2036 void evel_store_nv_pair_name(char * const item)
2038 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2042 /***************************************************************************/
2043 /* Get the latest nv pairs. This also performs the required checks. */
2044 /***************************************************************************/
2045 nv_pairs = evel_get_last_nv_pairs();
2047 /***************************************************************************/
2048 /* Store the item. */
2049 /***************************************************************************/
2050 dlist_push_last(&nv_pairs->suppressed_nv_pair_names, item);
2055 /**************************************************************************//**
2056 * Store a "suppressedFieldNames" item in the working throttle spec.
2058 * @param item The item to store.
2059 *****************************************************************************/
2060 void evel_store_suppressed_field_name(char * const item)
2064 /***************************************************************************/
2065 /* Check preconditions. */
2066 /***************************************************************************/
2067 assert(evel_temp_throttle != NULL);
2069 /***************************************************************************/
2070 /* Store the item. */
2071 /***************************************************************************/
2072 dlist_push_last(&evel_temp_throttle->suppressed_field_names, item);
2077 /**************************************************************************//**
2078 * Get the last added suppressed nv pairs list entry in the working spec.
2080 * @returns The last entry.
2081 *****************************************************************************/
2082 EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs()
2084 DLIST_ITEM * dlist_item;
2085 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2089 /***************************************************************************/
2090 /* Check preconditions. */
2091 /***************************************************************************/
2092 assert(evel_temp_throttle != NULL);
2094 /***************************************************************************/
2095 /* Get the pair that was added when we opened the list entry. */
2096 /***************************************************************************/
2097 dlist_item = dlist_get_last(&evel_temp_throttle->suppressed_nv_pairs_list);
2098 assert(dlist_item != NULL);
2099 nv_pairs = dlist_item->item;
2100 assert(nv_pairs != NULL);