1 /**************************************************************************//**
5 * Simple event manager that is responsible for taking events (Heartbeats,
6 * Faults and Measurements) from the ring-buffer and posting them to the API.
11 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 * http://www.apache.org/licenses/LICENSE-2.0
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *****************************************************************************/
33 #include "evel_throttle.h"
35 /*****************************************************************************/
36 /* The Event Throttling State for all domains, indexed by */
37 /* ::EVEL_EVENT_DOMAINS, corresponding to JSON eventDomain. */
39 /* A given domain is in a throttled state if ::evel_throttle_spec is */
41 /*****************************************************************************/
42 static EVEL_THROTTLE_SPEC * evel_throttle_spec[EVEL_MAX_DOMAINS];
44 /*****************************************************************************/
45 /* The current measurement interval. Default: MEASUREMENT_INTERVAL_UKNOWN. */
46 /* Must be protected by evel_measurement_interval_mutex. */
47 /*****************************************************************************/
48 static int evel_measurement_interval;
50 /*****************************************************************************/
51 /* Mutex protecting evel_measurement_interval from contention between an */
52 /* EVEL client reading it, and the EVEL event handler updating it. */
53 /*****************************************************************************/
54 static pthread_mutex_t evel_measurement_interval_mutex;
56 /*****************************************************************************/
57 /* Flag stating that we have received a "provideThrottlingState" command. */
58 /* Set during JSON processing and cleared on sending the throttling state. */
59 /*****************************************************************************/
60 static bool evel_provide_throttling_state;
62 /*****************************************************************************/
63 /* Holder for the "commandType" value during JSON processing. */
64 /*****************************************************************************/
65 static char * evel_command_type_value;
67 /*****************************************************************************/
68 /* Holder for the "measurementInterval" value during JSON processing. */
69 /*****************************************************************************/
70 static char * evel_measurement_interval_value;
72 /*****************************************************************************/
73 /* Holder for the "eventDomain" value during JSON processing. */
74 /*****************************************************************************/
75 static char * evel_throttle_spec_domain_value;
77 /*****************************************************************************/
78 /* Decoded version of ::evel_throttle_spec_domain_value. */
79 /*****************************************************************************/
80 static EVEL_EVENT_DOMAINS evel_throttle_spec_domain;
82 /*****************************************************************************/
83 /* During JSON processing of a single throttling specification, we collect */
84 /* parameters in this working ::EVEL_THROTTLE_SPEC */
85 /*****************************************************************************/
86 static EVEL_THROTTLE_SPEC * evel_temp_throttle;
88 /*****************************************************************************/
89 /* State tracking our progress through the command list */
90 /*****************************************************************************/
91 EVEL_JSON_COMMAND_STATE evel_json_command_state;
93 /*****************************************************************************/
94 /* Debug strings for ::EVEL_JSON_COMMAND_STATE. */
95 /*****************************************************************************/
96 static const char * const evel_jcs_strings[EVEL_JCS_MAX] = {
98 "EVEL_JCS_COMMAND_LIST",
99 "EVEL_JCS_COMMAND_LIST_ENTRY",
102 "EVEL_JCS_FIELD_NAMES",
103 "EVEL_JCS_PAIRS_LIST",
104 "EVEL_JCS_PAIRS_LIST_ENTRY",
105 "EVEL_JCS_NV_PAIR_NAMES"
108 /*****************************************************************************/
109 /* Debug strings for JSON token type. */
110 /*****************************************************************************/
111 #define JSON_TOKEN_TYPES (JSMN_PRIMITIVE + 1)
112 static const char * const evel_json_token_strings[JSON_TOKEN_TYPES] = {
120 /*****************************************************************************/
121 /* Debug strings for JSON domains. */
122 /*****************************************************************************/
123 static const char * evel_domain_strings[EVEL_MAX_DOMAINS] = {
127 "measurementsForVfScaling",
137 /*****************************************************************************/
138 /* Local prototypes. */
139 /*****************************************************************************/
140 static void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec);
141 static struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys);
142 static void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec);
143 static void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
144 static void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
145 const MEMORY_CHUNK * const chunk);
146 static bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
147 const int num_required,
148 const EVEL_JSON_STATE new_state);
149 static void evel_stack_pop(EVEL_JSON_STACK * const json_stack);
150 static void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack);
151 static char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
152 const jsmntok_t * const token);
153 static void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
154 const jsmntok_t * const token);
155 static void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
156 const jsmntok_t * const token);
157 static void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
158 const jsmntok_t * const token);
159 static void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state);
160 static void evel_debug_token(const MEMORY_CHUNK * const chunk,
161 const jsmntok_t * const token);
162 static void evel_command_list_response(MEMORY_CHUNK * const post);
163 static int evel_json_encode_throttle(char * const json, const int max_size);
164 static int evel_json_encode_throttle_spec(char * const json,
166 const EVEL_EVENT_DOMAINS domain);
167 static int evel_json_encode_nv_pairs(char * const json,
169 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
170 static void evel_close_command();
171 static void evel_open_command();
172 static void evel_set_throttling_spec();
173 static void evel_set_measurement_interval();
174 static void evel_open_throttle_spec();
175 static void evel_close_throttle_spec();
176 static EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value);
177 static void evel_open_nv_pairs_list_entry();
178 static void evel_close_nv_pairs_list_entry();
179 static void evel_store_nv_pair_field_name(char * const value);
180 static void evel_store_nv_pair_name(char * const item);
181 static void evel_store_suppressed_field_name(char * const item);
182 static EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs();
184 /**************************************************************************//**
185 * Return the current measurement interval provided by the Event Listener.
187 * @returns The current measurement interval
188 * @retval EVEL_MEASUREMENT_INTERVAL_UKNOWN (0) - interval has not been
190 *****************************************************************************/
191 int evel_get_measurement_interval()
197 /***************************************************************************/
198 /* Lock, read, unlock. */
199 /***************************************************************************/
200 pthread_mutex_lock(&evel_measurement_interval_mutex);
201 result = evel_measurement_interval;
202 pthread_mutex_unlock(&evel_measurement_interval_mutex);
209 /**************************************************************************//**
210 * Return the ::EVEL_THROTTLE_SPEC for a given domain.
212 * @param domain The domain for which to return state.
213 *****************************************************************************/
214 EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain)
216 EVEL_THROTTLE_SPEC * result;
220 /***************************************************************************/
221 /* Check preconditions. */
222 /***************************************************************************/
223 assert(domain < EVEL_MAX_DOMAINS);
225 result = evel_throttle_spec[domain];
232 /**************************************************************************//**
233 * Determine whether a field_name should be suppressed.
235 * @param throttle_spec Throttle specification for the domain being encoded.
236 * @param field_name The field name to encoded or suppress.
237 * @return true if the field_name should be suppressed, false otherwise.
238 *****************************************************************************/
239 bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC * throttle_spec,
240 const char * const field_name)
242 bool suppress = false;
246 /***************************************************************************/
247 /* Check preconditions. */
248 /***************************************************************************/
249 assert(field_name != NULL);
251 /***************************************************************************/
252 /* If the throttle spec and hash table exist, query the field_names table. */
253 /***************************************************************************/
254 if ((throttle_spec != NULL) && (throttle_spec->hash_field_names != NULL))
258 hash_query.key = (char * const) field_name;
259 suppress = (hsearch_r(hash_query,
262 throttle_spec->hash_field_names) != 0);
270 /**************************************************************************//**
271 * Determine whether a name-value pair should be allowed (not suppressed).
273 * @param throttle_spec Throttle specification for the domain being encoded.
274 * @param field_name The field name holding the name-value pairs.
275 * @param name The name of the name-value pair to encoded or suppress.
276 * @return true if the name-value pair should be suppressed, false otherwise.
277 *****************************************************************************/
278 bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC * throttle_spec,
279 const char * const field_name,
280 const char * const name)
282 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
284 bool suppress = false;
288 /***************************************************************************/
289 /* Check preconditions. */
290 /***************************************************************************/
291 assert(field_name != NULL);
292 assert(name != NULL);
294 /***************************************************************************/
295 /* If the throttle spec and hash table exist, query the nv_pairs table. */
296 /***************************************************************************/
297 if ((throttle_spec != NULL) && (throttle_spec->hash_nv_pairs_list != NULL))
301 hash_query.key = (char * const) field_name;
302 hit = (hsearch_r(hash_query,
305 throttle_spec->hash_nv_pairs_list) != 0);
308 nv_pairs = hash_result->data;
312 /***************************************************************************/
313 /* If we got a hit, and the nv_pairs and hash table exist, query the */
314 /* nv_pairs table. */
315 /***************************************************************************/
316 if (hit && (nv_pairs != NULL) && (nv_pairs->hash_nv_pair_names != NULL))
320 hash_query.key = (char * const) name;
321 suppress = (hsearch_r(hash_query,
324 nv_pairs->hash_nv_pair_names) != 0);
332 /**************************************************************************//**
333 * Initialize event throttling to the default state.
335 * Called from ::evel_initialize.
336 *****************************************************************************/
337 void evel_throttle_initialize()
344 for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
346 evel_throttle_spec[ii] = NULL;
349 pthread_rc = pthread_mutex_init(&evel_measurement_interval_mutex, NULL);
350 assert(pthread_rc == 0);
352 evel_measurement_interval = EVEL_MEASUREMENT_INTERVAL_UKNOWN;
357 /**************************************************************************//**
358 * Clean up event throttling.
360 * Called from ::evel_terminate.
361 *****************************************************************************/
362 void evel_throttle_terminate()
369 for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
371 if (evel_throttle_spec[ii] != NULL)
373 evel_throttle_free(evel_throttle_spec[ii]);
374 evel_throttle_spec[ii] = NULL;
378 pthread_rc = pthread_mutex_destroy(&evel_measurement_interval_mutex);
379 assert(pthread_rc == 0);
384 /**************************************************************************//**
385 * Finalize a single ::EVEL_THROTTLE_SPEC.
387 * Now that the specification is collected, build hash tables to simplify the
390 * @param throttle_spec The ::EVEL_THROTTLE_SPEC to finalize.
391 *****************************************************************************/
392 void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec)
395 DLIST_ITEM * dlist_item;
400 /***************************************************************************/
401 /* Check preconditions. */
402 /***************************************************************************/
403 assert(throttle_spec != NULL);
405 /***************************************************************************/
406 /* Populate the hash table for suppressed field names. */
407 /***************************************************************************/
408 throttle_spec->hash_field_names =
409 evel_throttle_hash_create(&throttle_spec->suppressed_field_names);
411 /***************************************************************************/
412 /* Create the hash table for suppressed nv pairs. */
413 /***************************************************************************/
414 nv_pairs_count = dlist_count(&throttle_spec->suppressed_nv_pairs_list);
415 if (nv_pairs_count > 0)
417 throttle_spec->hash_nv_pairs_list = calloc(1, sizeof(struct hsearch_data));
418 assert(throttle_spec->hash_nv_pairs_list != NULL);
420 /*************************************************************************/
421 /* Provide plenty of space in the table - see hcreate_r notes. */
422 /*************************************************************************/
423 if (hcreate_r(nv_pairs_count * 2, throttle_spec->hash_nv_pairs_list) == 0)
425 EVEL_ERROR("Failed to create hash table");
426 free(throttle_spec->hash_nv_pairs_list);
427 throttle_spec->hash_nv_pairs_list = NULL;
431 /***************************************************************************/
432 /* Populate the hash tables under suppressed field names. */
433 /***************************************************************************/
434 dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
435 while (dlist_item != NULL)
437 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs = dlist_item->item;
440 /*************************************************************************/
441 /* Set the key to the string, and the item to the nv_pairs. */
442 /*************************************************************************/
443 assert(nv_pairs != NULL);
444 hash_add.key = nv_pairs->nv_pair_field_name;
445 hash_add.data = nv_pairs;
446 hsearch_r(hash_add, ENTER, &add_result, throttle_spec->hash_nv_pairs_list);
448 /*************************************************************************/
449 /* Create the nv_pair_names hash since we're in here. */
450 /*************************************************************************/
451 nv_pairs->hash_nv_pair_names =
452 evel_throttle_hash_create(&nv_pairs->suppressed_nv_pair_names);
454 dlist_item = dlist_get_next(dlist_item);
460 /**************************************************************************//**
461 * Create and populate a hash table from a DLIST of keys.
463 * @param hash_keys Pointer to a DLIST of hash table keys.
464 * @return Pointer to the created hash-table, or NULL on failure.
465 *****************************************************************************/
466 struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys)
469 struct hsearch_data * hash_table;
474 /***************************************************************************/
475 /* Check preconditions. */
476 /***************************************************************************/
477 assert(hash_keys != NULL);
479 /***************************************************************************/
480 /* Count the keys and if there are any, populate the hash table with them. */
481 /***************************************************************************/
482 key_count = dlist_count(hash_keys);
485 EVEL_DEBUG("Populating table for %d keys", key_count);
487 hash_table = calloc(1, sizeof(struct hsearch_data));
488 assert(hash_table != NULL);
490 /*************************************************************************/
491 /* We need to leave plenty of space in the table - see hcreate_r notes. */
492 /*************************************************************************/
493 if (hcreate_r(key_count * 2, hash_table) != 0)
495 DLIST_ITEM * dlist_item;
496 dlist_item = dlist_get_first(hash_keys);
497 while (dlist_item != NULL)
499 assert(dlist_item->item != NULL);
501 /*********************************************************************/
502 /* Set the key and data to the item, which is a string in this case. */
503 /*********************************************************************/
505 hash_add.key = dlist_item->item;
506 hash_add.data = dlist_item->item;
507 hsearch_r(hash_add, ENTER, &add_result, hash_table);
508 dlist_item = dlist_get_next(dlist_item);
513 EVEL_ERROR("Failed to create hash table");
528 /**************************************************************************//**
529 * Free resources associated with a single ::EVEL_THROTTLE_SPEC.
531 * @param throttle_spec The ::EVEL_THROTTLE_SPEC to free.
532 *****************************************************************************/
533 void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec)
536 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
540 /***************************************************************************/
541 /* Check preconditions. */
542 /***************************************************************************/
543 assert(throttle_spec != NULL);
545 /***************************************************************************/
546 /* Free any hash tables. */
547 /***************************************************************************/
548 if (throttle_spec->hash_field_names != NULL)
550 hdestroy_r(throttle_spec->hash_field_names);
551 free(throttle_spec->hash_field_names);
553 if (throttle_spec->hash_nv_pairs_list != NULL)
555 hdestroy_r(throttle_spec->hash_nv_pairs_list);
556 free(throttle_spec->hash_nv_pairs_list);
559 /***************************************************************************/
560 /* Iterate through the linked lists, freeing memory. */
561 /***************************************************************************/
562 field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
563 while (field_name != NULL)
566 field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
569 nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
570 while (nv_pairs != NULL)
572 evel_throttle_free_nv_pair(nv_pairs);
573 nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
581 /**************************************************************************//**
582 * Free resources associated with a single ::EVEL_SUPPRESSED_NV_PAIR.
584 * @param nv_pair The ::EVEL_SUPPRESSED_NV_PAIR to free.
585 *****************************************************************************/
586 void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
588 char * suppressed_name;
592 /***************************************************************************/
593 /* Check preconditions. */
594 /***************************************************************************/
595 assert(nv_pairs != NULL);
597 /***************************************************************************/
598 /* Free any hash tables. */
599 /***************************************************************************/
600 if (nv_pairs->hash_nv_pair_names != NULL)
602 hdestroy_r(nv_pairs->hash_nv_pair_names);
603 free(nv_pairs->hash_nv_pair_names);
606 /***************************************************************************/
607 /* Iterate through the linked lists, freeing memory. */
608 /***************************************************************************/
609 suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
610 while (suppressed_name != NULL)
612 free(suppressed_name);
613 suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
615 if (nv_pairs->nv_pair_field_name != NULL)
617 free(nv_pairs->nv_pair_field_name);
624 /**************************************************************************//**
625 * Handle a JSON response from the listener, as a list of tokens from JSMN.
627 * @param chunk Memory chunk containing the JSON buffer.
628 * @param json_tokens Array of tokens to handle.
629 * @param num_tokens The number of tokens to handle.
630 * @param post The memory chunk in which to place any resulting POST.
631 * @return true if the command was handled, false otherwise.
632 *****************************************************************************/
633 bool evel_handle_command_list(const MEMORY_CHUNK * const chunk,
634 const jsmntok_t * const json_tokens,
635 const int num_tokens,
636 MEMORY_CHUNK * const post)
638 EVEL_JSON_STACK stack;
639 EVEL_JSON_STACK * json_stack = &stack;
640 EVEL_JSON_STACK_ENTRY * entry;
647 /***************************************************************************/
648 /* Check preconditions. */
649 /***************************************************************************/
650 assert(chunk != NULL);
651 assert(json_tokens != NULL);
652 assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS);
654 /***************************************************************************/
655 /* Collect one top-level item. */
656 /***************************************************************************/
657 evel_init_json_stack(json_stack, chunk);
659 /***************************************************************************/
660 /* Initialize JSON processing variables. */
661 /***************************************************************************/
662 evel_provide_throttling_state = false;
663 evel_command_type_value = NULL;
664 evel_measurement_interval_value = NULL;
665 evel_throttle_spec_domain_value = NULL;
666 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
667 evel_temp_throttle = NULL;
668 evel_json_command_state = EVEL_JCS_START;
670 /***************************************************************************/
671 /* Loop through the tokens, keeping a stack of state representing the */
672 /* nested JSON structure (see json_state). We also track our way through */
673 /* the ::EVEL_JSON_COMMAND_STATE as we go. */
674 /***************************************************************************/
675 while (json_ok && (token_index < num_tokens))
677 const jsmntok_t * const token = &json_tokens[token_index];
681 evel_debug_token(chunk, token);
684 /*************************************************************************/
685 /* We may have popped or pushed, so always re-evaluate the stack entry. */
686 /*************************************************************************/
687 entry = &json_stack->entry[json_stack->level];
692 if ((entry->json_state == EVEL_JSON_ITEM) ||
693 (entry->json_state == EVEL_JSON_VALUE))
695 json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_KEY);
699 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
700 entry->json_state, token_index, token->type);
706 if ((entry->json_state == EVEL_JSON_ITEM) ||
707 (entry->json_state == EVEL_JSON_VALUE))
709 json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_ITEM);
713 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
714 entry->json_state, token_index, token->type);
720 if (entry->json_state == EVEL_JSON_KEY)
722 evel_stack_store_key(json_stack, token);
724 else if (entry->json_state == EVEL_JSON_VALUE)
726 evel_stack_store_value(json_stack, token);
728 else if (entry->json_state == EVEL_JSON_ITEM)
730 evel_stack_store_item(json_stack, token);
734 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
735 entry->json_state, token_index, token->type);
741 if (entry->json_state == EVEL_JSON_VALUE)
743 evel_stack_store_value(json_stack, token);
745 else if (entry->json_state == EVEL_JSON_ITEM)
747 evel_stack_store_item(json_stack, token);
751 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
752 entry->json_state, token_index, token->type);
759 EVEL_ERROR("Unexpected JSON format at token %d (%d)",
760 token_index, token->type);
765 /*************************************************************************/
766 /* Pop the stack if we're counted enough nested items. */
767 /*************************************************************************/
768 evel_stack_pop(json_stack);
773 /***************************************************************************/
774 /* Cleanup the stack - we may have exited without winding it back, if the */
775 /* input was not well formed. */
776 /***************************************************************************/
777 evel_stack_cleanup(json_stack);
779 /***************************************************************************/
780 /* We may want to generate and POST a response to the command list. */
781 /***************************************************************************/
784 evel_command_list_response(post);
787 /***************************************************************************/
788 /* Make sure we're clean on exit. */
789 /***************************************************************************/
790 assert(evel_command_type_value == NULL);
791 assert(evel_measurement_interval_value == NULL);
792 assert(evel_throttle_spec_domain_value == NULL);
793 assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
794 assert(evel_temp_throttle == NULL);
801 /**************************************************************************//**
802 * Copy a copy of an element, in string form.
804 * The caller must manage memory allocated for the copied string.
806 * @param chunk Memory chunk containing the JSON buffer.
807 * @param token The token to copy from.
808 * @return the copy of the element.
809 *****************************************************************************/
810 char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
811 const jsmntok_t * const token)
818 /***************************************************************************/
819 /* Call strdup to copy the string, inserting a temporary \0 for the call. */
820 /***************************************************************************/
821 temp_char = chunk->memory[token->end];
822 chunk->memory[token->end] = '\0';
823 result = strdup(chunk->memory + token->start);
824 assert(result != NULL);
825 chunk->memory[token->end] = temp_char;
832 /**************************************************************************//**
833 * Copy a copy of an element, in string form.
835 * @param json_stack The JSON stack to initialize.
836 * @param chunk The underlying memory chunk used for parsing.
837 *****************************************************************************/
838 void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
839 const MEMORY_CHUNK * const chunk)
841 EVEL_JSON_STACK_ENTRY * entry;
845 json_stack->level = 0;
846 entry = json_stack->entry;
847 entry->json_state = EVEL_JSON_ITEM;
848 entry->json_count = 0;
849 entry->num_required = 1;
850 entry->json_key = NULL;
851 json_stack->chunk = chunk;
856 /**************************************************************************//**
857 * Push a new entry on the stack
859 * @param json_stack The stack.
860 * @param num_required The number of elements required.
861 * @param new_state The state for the new entry.
862 * @return false if we cannot push onto the stack.
863 *****************************************************************************/
864 bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
865 const int num_required,
866 const EVEL_JSON_STATE new_state)
868 EVEL_JSON_STACK_ENTRY * entry;
874 /***************************************************************************/
875 /* Check preconditions. */
876 /***************************************************************************/
877 assert(json_stack != NULL);
878 assert(json_stack->level >= 0);
879 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
880 assert((new_state == EVEL_JSON_ITEM) || (new_state == EVEL_JSON_KEY));
882 /***************************************************************************/
883 /* Check nesting depth, and stop processing if we hit the limit. */
884 /***************************************************************************/
885 if ((json_stack->level + 1) >= EVEL_JSON_STACK_DEPTH)
887 EVEL_ERROR("JSON Nesting is too deep - stop processing");
892 /***************************************************************************/
893 /* Evaluate cases where we recurse and are interested in the contents. */
894 /***************************************************************************/
895 entry = &json_stack->entry[json_stack->level];
896 key = entry->json_key;
898 /***************************************************************************/
899 /* Note that this is the key before we drop a level. */
900 /***************************************************************************/
903 EVEL_DEBUG("Push with key: %s", key);
905 switch (evel_json_command_state)
908 if (strcmp(key, "commandList") == 0)
910 evel_set_command_state(EVEL_JCS_COMMAND_LIST);
914 case EVEL_JCS_COMMAND_LIST_ENTRY:
915 if (strcmp(key, "command") == 0)
918 evel_set_command_state(EVEL_JCS_COMMAND);
922 case EVEL_JCS_COMMAND:
923 if (strcmp(key, "eventDomainThrottleSpecification") == 0)
925 evel_open_throttle_spec();
926 evel_set_command_state(EVEL_JCS_SPEC);
931 if (strcmp(key, "suppressedFieldNames") == 0)
933 evel_set_command_state(EVEL_JCS_FIELD_NAMES);
935 else if (strcmp(key, "suppressedNvPairsList") == 0)
937 evel_set_command_state(EVEL_JCS_PAIRS_LIST);
941 case EVEL_JCS_PAIRS_LIST_ENTRY:
942 if (strcmp(key, "suppressedNvPairNames") == 0)
944 evel_set_command_state(EVEL_JCS_NV_PAIR_NAMES);
948 case EVEL_JCS_FIELD_NAMES:
949 case EVEL_JCS_PAIRS_LIST:
950 case EVEL_JCS_NV_PAIR_NAMES:
952 EVEL_ERROR("Unexpected JSON key %s in state %d",
954 evel_json_command_state);
960 EVEL_DEBUG("Push with no key");
962 /*************************************************************************/
963 /* If we're pushing without a key, then we're in an array. We switch */
964 /* state based on the existing state and stack level. */
965 /*************************************************************************/
966 const int COMMAND_LIST_LEVEL = 2;
967 const int NV_PAIRS_LIST_LEVEL = 6;
969 if ((evel_json_command_state == EVEL_JCS_PAIRS_LIST) &&
970 (json_stack->level == NV_PAIRS_LIST_LEVEL))
972 /***********************************************************************/
973 /* We are entering an object within the "suppressedNvPairsList" array. */
974 /***********************************************************************/
975 evel_open_nv_pairs_list_entry();
976 evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
979 if ((evel_json_command_state == EVEL_JCS_COMMAND_LIST) &&
980 (json_stack->level == COMMAND_LIST_LEVEL))
982 /***********************************************************************/
983 /* We are entering an object within the "commandList" array. */
984 /***********************************************************************/
985 evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
989 /***************************************************************************/
990 /* Push the stack and initialize the entry. */
991 /***************************************************************************/
994 EVEL_DEBUG("Stack Push -> %d", json_stack->level);
995 entry = &json_stack->entry[json_stack->level];
996 entry->json_count = 0;
997 entry->num_required = num_required;
998 entry->json_state = new_state;
999 entry->json_key = NULL;
1009 /**************************************************************************//**
1010 * Pop any stack entries which have collected the required number of items.
1012 * @param json_stack The stack.
1013 *****************************************************************************/
1014 void evel_stack_pop(EVEL_JSON_STACK * const json_stack)
1016 EVEL_JSON_STACK_ENTRY * entry;
1021 /***************************************************************************/
1022 /* Check preconditions. */
1023 /***************************************************************************/
1024 assert(json_stack != NULL);
1025 assert(json_stack->level >= 0);
1026 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1028 entry = &json_stack->entry[json_stack->level];
1029 while ((json_stack->level > 0) && (entry->json_count == entry->num_required))
1031 key = entry->json_key;
1033 switch (evel_json_command_state)
1035 case EVEL_JCS_COMMAND_LIST:
1036 evel_set_command_state(EVEL_JCS_START);
1039 case EVEL_JCS_COMMAND_LIST_ENTRY:
1040 evel_set_command_state(EVEL_JCS_COMMAND_LIST);
1043 case EVEL_JCS_COMMAND:
1044 evel_close_command();
1045 evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
1049 evel_close_throttle_spec();
1050 evel_set_command_state(EVEL_JCS_COMMAND);
1053 case EVEL_JCS_FIELD_NAMES:
1054 evel_set_command_state(EVEL_JCS_SPEC);
1057 case EVEL_JCS_PAIRS_LIST:
1058 evel_set_command_state(EVEL_JCS_SPEC);
1061 case EVEL_JCS_PAIRS_LIST_ENTRY:
1062 evel_close_nv_pairs_list_entry();
1063 evel_set_command_state(EVEL_JCS_PAIRS_LIST);
1066 case EVEL_JCS_NV_PAIR_NAMES:
1067 evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
1074 /*************************************************************************/
1075 /* Free off any key that was duplicated and stored. */
1076 /*************************************************************************/
1080 entry->json_key = NULL;
1083 /*************************************************************************/
1084 /* We just reached the required number of key-value pairs or items, so */
1085 /* pop the stack. */
1086 /*************************************************************************/
1087 json_stack->level--;
1090 EVEL_DEBUG("Stack Pop -> %d", json_stack->level);
1092 /*************************************************************************/
1093 /* We just completed collection of an ITEM (within an ARRAY) or a VALUE */
1094 /* (within an OBJECT). Either way, we need to count it. */
1095 /*************************************************************************/
1096 entry->json_count++;
1098 /*************************************************************************/
1099 /* If we just completed a VALUE, then we expect the next element to be a */
1100 /* key, if there is a next element. */
1101 /*************************************************************************/
1102 if (entry->json_state == EVEL_JSON_VALUE)
1104 entry->json_state = EVEL_JSON_KEY;
1111 /**************************************************************************//**
1112 * Pop all stack entries, freeing any memory as we go.
1114 * @param json_stack The stack.
1115 *****************************************************************************/
1116 void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack)
1118 EVEL_JSON_STACK_ENTRY * entry;
1122 /***************************************************************************/
1123 /* Check preconditions. */
1124 /***************************************************************************/
1125 assert(json_stack != NULL);
1126 assert(json_stack->level >= 0);
1127 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1129 entry = &json_stack->entry[json_stack->level];
1130 while ((json_stack->level > 0))
1132 /*************************************************************************/
1133 /* Free off any key that was duplicated and stored. */
1134 /*************************************************************************/
1135 if (entry->json_key != NULL)
1137 free(entry->json_key);
1138 entry->json_key = NULL;
1141 /*************************************************************************/
1142 /* We just reached the required number of key-value pairs or items, so */
1143 /* pop the stack. */
1144 /*************************************************************************/
1145 json_stack->level--;
1149 /***************************************************************************/
1150 /* If we hit EVEL_JSON_STACK_DEPTH, we exit the loop and can leave these */
1151 /* values hanging - so clean them up. */
1152 /***************************************************************************/
1153 if (evel_command_type_value != NULL)
1155 free(evel_command_type_value);
1156 evel_command_type_value = NULL;
1158 if (evel_measurement_interval_value != NULL)
1160 free(evel_measurement_interval_value);
1161 evel_measurement_interval_value = NULL;
1163 if (evel_throttle_spec_domain_value != NULL)
1165 free(evel_throttle_spec_domain_value);
1166 evel_throttle_spec_domain_value = NULL;
1168 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1169 if (evel_temp_throttle != NULL)
1171 evel_throttle_free(evel_temp_throttle);
1172 evel_temp_throttle = NULL;
1178 /**************************************************************************//**
1179 * Store a key in the JSON stack.
1181 * We always store the most recent key at each level in the stack.
1183 * @param json_stack The stack.
1184 * @param token The token holding the key.
1185 *****************************************************************************/
1186 void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
1187 const jsmntok_t * const token)
1189 EVEL_JSON_STACK_ENTRY * entry;
1193 /***************************************************************************/
1194 /* Check preconditions. */
1195 /***************************************************************************/
1196 assert(json_stack != NULL);
1197 assert(json_stack->level >= 0);
1198 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1200 /***************************************************************************/
1201 /* Free any previously stored key, replacing it with the new one. */
1202 /***************************************************************************/
1203 entry = &json_stack->entry[json_stack->level];
1204 if (entry->json_key != NULL)
1206 free(entry->json_key);
1208 entry->json_key = evel_stack_strdup(json_stack->chunk, token);
1210 /***************************************************************************/
1211 /* Switch state to collecting the corresponding value. */
1212 /***************************************************************************/
1213 entry->json_state = EVEL_JSON_VALUE;
1215 EVEL_DEBUG("Stored key: %s", entry->json_key);
1219 /**************************************************************************//**
1220 * Store a value in the JSON stack.
1222 * @param json_stack The stack.
1223 * @param token The token holding the value.
1224 *****************************************************************************/
1225 void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
1226 const jsmntok_t * const token)
1228 EVEL_JSON_STACK_ENTRY * entry;
1234 /***************************************************************************/
1235 /* Check preconditions. */
1236 /***************************************************************************/
1237 assert(json_stack != NULL);
1238 assert(json_stack->level >= 0);
1239 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1241 /***************************************************************************/
1242 /* Based on the (key, state), work out whether we're expecting a value, */
1243 /* then store or ignore it as required. */
1244 /***************************************************************************/
1245 entry = &json_stack->entry[json_stack->level];
1246 value = evel_stack_strdup(json_stack->chunk, token);
1248 EVEL_DEBUG("Store value: %s", value);
1250 switch (evel_json_command_state)
1252 case EVEL_JCS_COMMAND:
1253 if (strcmp(entry->json_key, "commandType") == 0)
1255 evel_command_type_value = value;
1258 else if (strcmp(entry->json_key, "measurementInterval") == 0)
1260 evel_measurement_interval_value = value;
1266 if (strcmp(entry->json_key, "eventDomain") == 0)
1268 evel_throttle_spec_domain_value = value;
1273 case EVEL_JCS_PAIRS_LIST_ENTRY:
1274 if (strcmp(entry->json_key, "nvPairFieldName") == 0)
1276 evel_store_nv_pair_field_name(value);
1282 EVEL_DEBUG("Ignoring value in state: %s",
1283 evel_jcs_strings[evel_json_command_state]);
1289 EVEL_DEBUG("Ignored value: %s", value);
1293 /***************************************************************************/
1294 /* Switch state to another key. */
1295 /***************************************************************************/
1296 entry->json_state = EVEL_JSON_KEY;
1298 /***************************************************************************/
1299 /* Count the key-value pair. */
1300 /***************************************************************************/
1301 entry->json_count++;
1306 /**************************************************************************//**
1307 * Store an item in the JSON stack - a string or primitive in an array.
1309 * @param json_stack The stack.
1310 * @param token The token holding the item.
1311 *****************************************************************************/
1312 void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
1313 const jsmntok_t * const token)
1315 EVEL_JSON_STACK_ENTRY * entry;
1321 /***************************************************************************/
1322 /* Check preconditions. */
1323 /***************************************************************************/
1324 assert(json_stack != NULL);
1325 assert(json_stack->level >= 0);
1326 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1328 /***************************************************************************/
1329 /* Based on the state, work out whether we're expecting an item, then */
1330 /* store or ignore it as required. */
1331 /***************************************************************************/
1332 entry = &json_stack->entry[json_stack->level];
1333 item = evel_stack_strdup(json_stack->chunk, token);
1335 EVEL_DEBUG("Store item: %s", item);
1337 switch (evel_json_command_state)
1339 case EVEL_JCS_NV_PAIR_NAMES:
1340 evel_store_nv_pair_name(item);
1344 case EVEL_JCS_FIELD_NAMES:
1345 evel_store_suppressed_field_name(item);
1350 EVEL_DEBUG("Ignoring item in state: %s",
1351 evel_jcs_strings[evel_json_command_state]);
1357 EVEL_DEBUG("Ignored item: %s", item);
1361 /***************************************************************************/
1362 /* We need another item. This is purely defensive. */
1363 /***************************************************************************/
1364 entry->json_state = EVEL_JSON_ITEM;
1366 /***************************************************************************/
1367 /* Count the item. */
1368 /***************************************************************************/
1369 entry->json_count++;
1372 /**************************************************************************//**
1373 * Set the JSON command state to a new value.
1375 * @param new_state The new state to set.
1376 *****************************************************************************/
1377 void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state)
1381 /***************************************************************************/
1382 /* Check preconditions. */
1383 /***************************************************************************/
1384 assert(evel_json_command_state < EVEL_JCS_MAX);
1385 assert(new_state < EVEL_JCS_MAX);
1387 /***************************************************************************/
1388 /* Provide common debug, and set the new state. */
1389 /***************************************************************************/
1390 EVEL_DEBUG("Command State: %s -> %s",
1391 evel_jcs_strings[evel_json_command_state],
1392 evel_jcs_strings[new_state]);
1393 evel_json_command_state = new_state;
1398 /**************************************************************************//**
1399 * Produce debug output from a JSON token.
1401 * @param chunk Memory chunk containing the JSON buffer.
1402 * @param token Token to dump.
1403 *****************************************************************************/
1404 void evel_debug_token(const MEMORY_CHUNK * const chunk,
1405 const jsmntok_t * const token)
1411 /***************************************************************************/
1412 /* Check preconditions. */
1413 /***************************************************************************/
1414 assert(token->type > 0);
1415 assert(token->type < JSON_TOKEN_TYPES);
1417 /***************************************************************************/
1418 /* Log the token, leaving it in the state in which it started. */
1419 /***************************************************************************/
1420 temp_char = chunk->memory[token->end];
1421 chunk->memory[token->end] = '\0';
1422 EVEL_DEBUG("JSON token type: %s", evel_json_token_strings[token->type]);
1423 EVEL_DEBUG("JSON token: %s", chunk->memory + token->start);
1424 chunk->memory[token->end] = temp_char;
1429 /**************************************************************************//**
1430 * Post a response to the commandList.
1432 * @param post Memory chunk in which to post a response.
1433 *****************************************************************************/
1434 void evel_command_list_response(MEMORY_CHUNK * const post)
1440 /***************************************************************************/
1441 /* Check preconditions. */
1442 /***************************************************************************/
1443 assert(post != NULL);
1444 assert(post->memory == NULL);
1446 if (evel_provide_throttling_state)
1448 EVEL_DEBUG("Provide throttling state");
1450 /*************************************************************************/
1451 /* Encode the response, making it printf-able for debug. */
1452 /*************************************************************************/
1453 json_post = malloc(EVEL_MAX_JSON_BODY);
1454 assert(json_post != NULL);
1455 post->size = evel_json_encode_throttle(json_post, EVEL_MAX_JSON_BODY - 1);
1456 post->memory = json_post;
1457 post->memory[post->size] = '\0';
1458 evel_provide_throttling_state = false;
1464 /**************************************************************************//**
1465 * Encode the full throttling specification according to AT&T's schema.
1467 * @param json Pointer to where to store the JSON encoded data.
1468 * @param max_size Size of storage available in json_body.
1469 * @returns Number of bytes actually written.
1470 *****************************************************************************/
1471 int evel_json_encode_throttle(char * const json, const int max_size)
1480 /***************************************************************************/
1481 /* Check preconditions. */
1482 /***************************************************************************/
1483 assert(json != NULL);
1484 assert(max_size > 0);
1486 /***************************************************************************/
1487 /* Work out if we're throttled. */
1488 /***************************************************************************/
1490 for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1492 if (evel_throttle_spec[domain] != NULL)
1498 /***************************************************************************/
1499 /* Encode the response. */
1500 /***************************************************************************/
1502 offset += snprintf(json + offset, max_size - offset,
1503 "{\"eventThrottlingState\": {");
1504 offset += snprintf(json + offset, max_size - offset,
1505 "\"eventThrottlingMode\": \"%s\"",
1506 throttled ? "throttled" : "normal");
1509 offset += snprintf(json + offset, max_size - offset,
1510 ", \"eventDomainThrottleSpecificationList\": [");
1512 domain_added = false;
1513 for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1515 if (evel_throttle_spec[domain] != NULL)
1519 offset += snprintf(json + offset, max_size - offset, ", ");
1522 offset += evel_json_encode_throttle_spec(json + offset,
1525 domain_added = true;
1529 offset += snprintf(json + offset, max_size - offset, "]");
1532 offset += snprintf(json + offset, max_size - offset, "}}");
1539 /**************************************************************************//**
1540 * Encode a throttling specification for a domain.
1542 * @param json Pointer to where to store the JSON encoded data.
1543 * @param max_size Size of storage available in json_body.
1544 * @returns Number of bytes actually written.
1545 *****************************************************************************/
1546 int evel_json_encode_throttle_spec(char * const json,
1548 const EVEL_EVENT_DOMAINS domain)
1551 EVEL_THROTTLE_SPEC * throttle_spec;
1552 DLIST_ITEM * dlist_item;
1555 /***************************************************************************/
1556 /* Check preconditions. */
1557 /***************************************************************************/
1558 assert(domain >= EVEL_DOMAIN_FAULT);
1559 assert(domain < EVEL_MAX_DOMAINS);
1560 assert(evel_throttle_spec[domain] != NULL);
1562 throttle_spec = evel_throttle_spec[domain];
1564 /***************************************************************************/
1565 /* Encode the domain. */
1566 /***************************************************************************/
1568 offset += snprintf(json + offset, max_size - offset,
1570 offset += snprintf(json + offset, max_size - offset,
1571 "\"eventDomain\": \"%s\"",
1572 evel_domain_strings[domain]);
1574 /***************************************************************************/
1575 /* Encode "suppressedFieldNames". */
1576 /***************************************************************************/
1577 dlist_item = dlist_get_first(&throttle_spec->suppressed_field_names);
1578 if (dlist_item != NULL)
1580 offset += snprintf(json + offset, max_size - offset,
1581 ", \"suppressedFieldNames\": [");
1582 while (dlist_item != NULL)
1584 char * suppressed_field = dlist_item->item;
1585 assert(suppressed_field != NULL);
1587 offset += snprintf(json + offset, max_size - offset,
1588 "\"%s\"", suppressed_field);
1589 dlist_item = dlist_get_next(dlist_item);
1590 if (dlist_item != NULL)
1592 offset += snprintf(json + offset, max_size - offset, ", ");
1596 offset += snprintf(json + offset, max_size - offset, "]");
1599 /***************************************************************************/
1600 /* Encode "suppressedNvPairsList". */
1601 /***************************************************************************/
1602 dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
1603 if (dlist_item != NULL)
1605 offset += snprintf(json + offset, max_size - offset,
1606 ", \"suppressedNvPairsList\": [");
1607 while (dlist_item != NULL)
1609 offset += evel_json_encode_nv_pairs(json + offset,
1612 dlist_item = dlist_get_next(dlist_item);
1613 if (dlist_item != NULL)
1615 offset += snprintf(json + offset, max_size - offset, ", ");
1619 offset += snprintf(json + offset, max_size - offset, "]");
1622 offset += snprintf(json + offset, max_size - offset, "}");
1629 /**************************************************************************//**
1630 * Encode a single "suppressedNvPairsListEntry".
1632 * @param json Pointer to where to store the JSON encoded data.
1633 * @param max_size Size of storage available in json_body.
1634 * @returns Number of bytes actually written.
1635 *****************************************************************************/
1636 int evel_json_encode_nv_pairs(char * const json,
1638 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
1640 DLIST_ITEM * dlist_item;
1644 /***************************************************************************/
1645 /* Check preconditions. */
1646 /***************************************************************************/
1647 assert(nv_pairs != NULL);
1648 assert(nv_pairs->nv_pair_field_name != NULL);
1649 assert(!dlist_is_empty(&nv_pairs->suppressed_nv_pair_names));
1651 /***************************************************************************/
1653 /***************************************************************************/
1655 offset += snprintf(json + offset, max_size - offset, "{");
1656 offset += snprintf(json + offset, max_size - offset,
1657 "\"nvPairFieldName\": \"%s\"",
1658 nv_pairs->nv_pair_field_name);
1659 dlist_item = dlist_get_first(&nv_pairs->suppressed_nv_pair_names);
1660 offset += snprintf(json + offset, max_size - offset,
1661 ", \"suppressedNvPairNames\": [");
1662 while (dlist_item != NULL)
1664 name = dlist_item->item;
1665 assert(name != NULL);
1666 offset += snprintf(json + offset, max_size - offset, "\"%s\"", name);
1667 dlist_item = dlist_get_next(dlist_item);
1668 if (dlist_item != NULL)
1670 offset += snprintf(json + offset, max_size - offset, ", ");
1673 offset += snprintf(json + offset, max_size - offset, "]");
1674 offset += snprintf(json + offset, max_size - offset, "}");
1681 /**************************************************************************//**
1682 * Method called when we open a "command" object.
1683 *****************************************************************************/
1684 void evel_open_command()
1688 /***************************************************************************/
1689 /* Make some assertions. */
1690 /***************************************************************************/
1691 assert(evel_command_type_value == NULL);
1692 assert(evel_measurement_interval_value == NULL);
1697 /**************************************************************************//**
1698 * Method called when we close a "command" object.
1699 *****************************************************************************/
1700 void evel_close_command()
1704 /***************************************************************************/
1705 /* If a commandType was provided, fan out and handle it now what we have */
1706 /* fathered all related information. */
1708 /* Note that we handle throttling specification and measurement interval */
1709 /* updates immediately on closing the command (not the list). We could */
1710 /* reject *all* commands in a list if any of them are invalid, but we are */
1711 /* take a best-effort strategy here - any valid-looking command gets */
1712 /* implemented regardless of what follows. */
1713 /***************************************************************************/
1714 if (evel_command_type_value != NULL)
1716 EVEL_DEBUG("Closing command %s", evel_command_type_value);
1718 if (strcmp(evel_command_type_value, "provideThrottlingState") == 0)
1720 evel_provide_throttling_state = true;
1722 else if (strcmp(evel_command_type_value, "throttlingSpecification") == 0)
1724 evel_set_throttling_spec();
1726 else if (strcmp(evel_command_type_value, "measurementIntervalChange") == 0)
1728 evel_set_measurement_interval();
1732 EVEL_ERROR("Ignoring unknown commandType: %s\n",
1733 evel_command_type_value);
1736 /*************************************************************************/
1737 /* Free the captured "commandType" value. */
1738 /*************************************************************************/
1739 free(evel_command_type_value);
1740 evel_command_type_value = NULL;
1743 /***************************************************************************/
1744 /* There could be an unused working throttle spec at this point - if the */
1745 /* "throttlingSpecification" commandType was not provided, or an invalid */
1746 /* domain was provided, or was not provided at all. */
1747 /***************************************************************************/
1748 if (evel_temp_throttle != NULL)
1750 evel_throttle_free(evel_temp_throttle);
1751 evel_temp_throttle = NULL;
1754 /***************************************************************************/
1755 /* Similarly, the domain could be set. */
1756 /***************************************************************************/
1757 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1759 /***************************************************************************/
1760 /* There could be an unused measurement interval value at this point - if */
1761 /* the "measurementIntervalChange" command was not provided. */
1762 /***************************************************************************/
1763 if (evel_measurement_interval_value != NULL)
1765 free(evel_measurement_interval_value);
1766 evel_measurement_interval_value = NULL;
1772 /**************************************************************************//**
1773 * Set the provided throttling specification, when the command closes.
1774 *****************************************************************************/
1775 void evel_set_throttling_spec()
1779 if ((evel_throttle_spec_domain >= 0) &&
1780 (evel_throttle_spec_domain < EVEL_MAX_DOMAINS))
1782 EVEL_DEBUG("Updating throttle spec for domain: %s",
1783 evel_domain_strings[evel_throttle_spec_domain]);
1785 /*************************************************************************/
1786 /* Free off the previous throttle specification for the domain, if there */
1788 /*************************************************************************/
1789 if (evel_throttle_spec[evel_throttle_spec_domain] != NULL)
1791 evel_throttle_free(evel_throttle_spec[evel_throttle_spec_domain]);
1794 /*************************************************************************/
1795 /* Finalize the working throttling spec, if there is one. */
1796 /*************************************************************************/
1797 if (evel_temp_throttle != NULL)
1799 evel_throttle_finalize(evel_temp_throttle);
1802 /*************************************************************************/
1803 /* Replace the throttle specification for the domain with the working */
1804 /* throttle specification. This could be NULL, if an empty throttle */
1805 /* specification has been received for a domain. */
1806 /*************************************************************************/
1807 evel_throttle_spec[evel_throttle_spec_domain] = evel_temp_throttle;
1808 evel_temp_throttle = NULL;
1814 /**************************************************************************//**
1815 * Set the provided measurement interval, when the command closes.
1816 *****************************************************************************/
1817 void evel_set_measurement_interval()
1821 if (evel_measurement_interval_value != NULL)
1823 const long int value = strtol(evel_measurement_interval_value, NULL, 10);
1825 if ((value >= 0) && (value <= INT_MAX))
1827 /***********************************************************************/
1828 /* Lock, update, unlock. */
1829 /***********************************************************************/
1830 EVEL_DEBUG("Updating measurement interval to %d\n", value);
1832 pthread_mutex_lock(&evel_measurement_interval_mutex);
1833 evel_measurement_interval = value;
1834 pthread_mutex_unlock(&evel_measurement_interval_mutex);
1838 EVEL_ERROR("Ignoring invalid measurement interval: %s",
1839 evel_measurement_interval_value);
1846 /**************************************************************************//**
1847 * Method called when we open an "eventDomainThrottleSpecification" object.
1848 *****************************************************************************/
1849 void evel_open_throttle_spec()
1853 /***************************************************************************/
1854 /* Check preconditions. */
1855 /***************************************************************************/
1856 assert(evel_throttle_spec_domain_value == NULL);
1857 assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
1858 assert(evel_temp_throttle == NULL);
1860 /***************************************************************************/
1861 /* Allocate and initialize an ::EVEL_THROTTLE_SPEC in which to hold */
1862 /* captured JSON elements. */
1863 /***************************************************************************/
1864 evel_temp_throttle = malloc(sizeof(EVEL_THROTTLE_SPEC));
1865 assert(evel_temp_throttle != NULL);
1866 dlist_initialize(&evel_temp_throttle->suppressed_field_names);
1867 dlist_initialize(&evel_temp_throttle->suppressed_nv_pairs_list);
1868 evel_temp_throttle->hash_field_names = NULL;
1869 evel_temp_throttle->hash_nv_pairs_list = NULL;
1874 /**************************************************************************//**
1875 * Method called when we close an "eventDomainThrottleSpecification" object.
1876 *****************************************************************************/
1877 void evel_close_throttle_spec()
1881 /***************************************************************************/
1882 /* Decode, free and blank a captured event domain value. */
1883 /***************************************************************************/
1884 if (evel_throttle_spec_domain_value != NULL)
1886 evel_throttle_spec_domain =
1887 evel_decode_domain(evel_throttle_spec_domain_value);
1888 free(evel_throttle_spec_domain_value);
1889 evel_throttle_spec_domain_value = NULL;
1892 /***************************************************************************/
1893 /* Free off an empty working throttle spec, to stop it being used. This */
1894 /* state should be represented by a NULL pointer for the domain. */
1895 /***************************************************************************/
1896 if (evel_temp_throttle != NULL)
1898 if (dlist_is_empty(&evel_temp_throttle->suppressed_field_names) &&
1899 dlist_is_empty(&evel_temp_throttle->suppressed_nv_pairs_list))
1901 free(evel_temp_throttle);
1902 evel_temp_throttle = NULL;
1909 /**************************************************************************//**
1910 * Convert a value for an "eventDomain" into an ::EVEL_EVENT_DOMAINS.
1912 * @param domain_value The domain string value to decode.
1913 * @returns The matching ::EVEL_EVENT_DOMAINS, or ::EVEL_MAX_DOMAINS on error.
1914 *****************************************************************************/
1915 EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value)
1917 EVEL_EVENT_DOMAINS result;
1922 /***************************************************************************/
1923 /* Check preconditions. */
1924 /***************************************************************************/
1925 assert(domain_value != NULL);
1927 result = EVEL_MAX_DOMAINS;
1928 for (ii = EVEL_DOMAIN_FAULT; ii < EVEL_MAX_DOMAINS; ii++)
1930 assert(evel_domain_strings[ii] != NULL);
1931 if (strcmp(evel_domain_strings[ii], domain_value) == 0)
1942 /**************************************************************************//**
1943 * Method called when we open a "suppressedNvPairsListEntry" object.
1944 *****************************************************************************/
1945 void evel_open_nv_pairs_list_entry()
1947 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1951 /***************************************************************************/
1952 /* Check preconditions. */
1953 /***************************************************************************/
1954 assert(evel_temp_throttle != NULL);
1956 /***************************************************************************/
1957 /* Allocate and initialize an ::EVEL_SUPPRESSED_NV_PAIRS, and add it to */
1959 /***************************************************************************/
1960 nv_pairs = malloc(sizeof(EVEL_SUPPRESSED_NV_PAIRS));
1961 assert(nv_pairs != NULL);
1962 nv_pairs->nv_pair_field_name = NULL;
1963 dlist_initialize(&nv_pairs->suppressed_nv_pair_names);
1964 nv_pairs->hash_nv_pair_names = NULL;
1965 dlist_push_last(&evel_temp_throttle->suppressed_nv_pairs_list, nv_pairs);
1970 /**************************************************************************//**
1971 * Method called when we close a "suppressedNvPairsListEntry" object.
1972 *****************************************************************************/
1973 void evel_close_nv_pairs_list_entry()
1975 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1976 EVEL_SUPPRESSED_NV_PAIRS * popped;
1980 /***************************************************************************/
1981 /* Get the latest nv pairs. This also performs the required checks. */
1982 /***************************************************************************/
1983 nv_pairs = evel_get_last_nv_pairs();
1985 /***************************************************************************/
1986 /* For a "suppressedNvPairsListEntry" to have any meaning, we need both */
1987 /* "nvPairFieldName" and "suppressedNvPairNames". If we don't, then pop */
1988 /* and free whatever we just collected. */
1989 /***************************************************************************/
1990 if ((nv_pairs->nv_pair_field_name == NULL) ||
1991 dlist_is_empty(&nv_pairs->suppressed_nv_pair_names))
1993 popped = dlist_pop_last(&evel_temp_throttle->suppressed_nv_pairs_list);
1994 assert(popped == nv_pairs);
1995 evel_throttle_free_nv_pair(popped);
2001 /**************************************************************************//**
2002 * Store an "nvPairFieldName" value in the working throttle spec.
2004 * @param value The value to store.
2005 *****************************************************************************/
2006 void evel_store_nv_pair_field_name(char * const value)
2008 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2012 /***************************************************************************/
2013 /* Get the latest nv pairs. This also performs the required checks. */
2014 /***************************************************************************/
2015 nv_pairs = evel_get_last_nv_pairs();
2017 /***************************************************************************/
2018 /* Store the value. */
2019 /***************************************************************************/
2020 nv_pairs->nv_pair_field_name = value;
2025 /**************************************************************************//**
2026 * Store a "suppressedNvPairNames" item in the working throttle spec.
2028 * @param item The item to store.
2029 *****************************************************************************/
2030 void evel_store_nv_pair_name(char * const item)
2032 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2036 /***************************************************************************/
2037 /* Get the latest nv pairs. This also performs the required checks. */
2038 /***************************************************************************/
2039 nv_pairs = evel_get_last_nv_pairs();
2041 /***************************************************************************/
2042 /* Store the item. */
2043 /***************************************************************************/
2044 dlist_push_last(&nv_pairs->suppressed_nv_pair_names, item);
2049 /**************************************************************************//**
2050 * Store a "suppressedFieldNames" item in the working throttle spec.
2052 * @param item The item to store.
2053 *****************************************************************************/
2054 void evel_store_suppressed_field_name(char * const item)
2058 /***************************************************************************/
2059 /* Check preconditions. */
2060 /***************************************************************************/
2061 assert(evel_temp_throttle != NULL);
2063 /***************************************************************************/
2064 /* Store the item. */
2065 /***************************************************************************/
2066 dlist_push_last(&evel_temp_throttle->suppressed_field_names, item);
2071 /**************************************************************************//**
2072 * Get the last added suppressed nv pairs list entry in the working spec.
2074 * @returns The last entry.
2075 *****************************************************************************/
2076 EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs()
2078 DLIST_ITEM * dlist_item;
2079 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2083 /***************************************************************************/
2084 /* Check preconditions. */
2085 /***************************************************************************/
2086 assert(evel_temp_throttle != NULL);
2088 /***************************************************************************/
2089 /* Get the pair that was added when we opened the list entry. */
2090 /***************************************************************************/
2091 dlist_item = dlist_get_last(&evel_temp_throttle->suppressed_nv_pairs_list);
2092 assert(dlist_item != NULL);
2093 nv_pairs = dlist_item->item;
2094 assert(nv_pairs != NULL);