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] = {
130 "measurementsForVfScaling",
142 /*****************************************************************************/
143 /* Local prototypes. */
144 /*****************************************************************************/
145 static void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec);
146 static struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys);
147 static void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec);
148 static void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
149 static void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
150 const MEMORY_CHUNK * const chunk);
151 static bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
152 const int num_required,
153 const EVEL_JSON_STATE new_state);
154 static void evel_stack_pop(EVEL_JSON_STACK * const json_stack);
155 static void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack);
156 static char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
157 const jsmntok_t * const token);
158 static void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
159 const jsmntok_t * const token);
160 static void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
161 const jsmntok_t * const token);
162 static void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
163 const jsmntok_t * const token);
164 static void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state);
165 static void evel_debug_token(const MEMORY_CHUNK * const chunk,
166 const jsmntok_t * const token);
167 static void evel_command_list_response(MEMORY_CHUNK * const post);
168 static int evel_json_encode_throttle(char * const json, const int max_size);
169 static int evel_json_encode_throttle_spec(char * const json,
171 const EVEL_EVENT_DOMAINS domain);
172 static int evel_json_encode_nv_pairs(char * const json,
174 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
175 static void evel_close_command();
176 static void evel_open_command();
177 static void evel_set_throttling_spec();
178 static void evel_set_measurement_interval();
179 static void evel_open_throttle_spec();
180 static void evel_close_throttle_spec();
181 static EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value);
182 static void evel_open_nv_pairs_list_entry();
183 static void evel_close_nv_pairs_list_entry();
184 static void evel_store_nv_pair_field_name(char * const value);
185 static void evel_store_nv_pair_name(char * const item);
186 static void evel_store_suppressed_field_name(char * const item);
187 static EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs();
189 /**************************************************************************//**
190 * Return the current measurement interval provided by the Event Listener.
192 * @returns The current measurement interval
193 * @retval EVEL_MEASUREMENT_INTERVAL_UKNOWN (0) - interval has not been
195 *****************************************************************************/
196 int evel_get_measurement_interval()
202 /***************************************************************************/
203 /* Lock, read, unlock. */
204 /***************************************************************************/
205 pthread_mutex_lock(&evel_measurement_interval_mutex);
206 result = evel_measurement_interval;
207 pthread_mutex_unlock(&evel_measurement_interval_mutex);
214 /**************************************************************************//**
215 * Return the ::EVEL_THROTTLE_SPEC for a given domain.
217 * @param domain The domain for which to return state.
218 *****************************************************************************/
219 EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain)
221 EVEL_THROTTLE_SPEC * result;
225 /***************************************************************************/
226 /* Check preconditions. */
227 /***************************************************************************/
228 assert(domain < EVEL_MAX_DOMAINS);
230 result = evel_throttle_spec[domain];
237 /**************************************************************************//**
238 * Determine whether a field_name should be suppressed.
240 * @param throttle_spec Throttle specification for the domain being encoded.
241 * @param field_name The field name to encoded or suppress.
242 * @return true if the field_name should be suppressed, false otherwise.
243 *****************************************************************************/
244 bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC * throttle_spec,
245 const char * const field_name)
247 bool suppress = false;
251 /***************************************************************************/
252 /* Check preconditions. */
253 /***************************************************************************/
254 assert(field_name != NULL);
256 /***************************************************************************/
257 /* If the throttle spec and hash table exist, query the field_names table. */
258 /***************************************************************************/
259 if ((throttle_spec != NULL) && (throttle_spec->hash_field_names != NULL))
263 hash_query.key = (char * const) field_name;
264 suppress = (hsearch_r(hash_query,
267 throttle_spec->hash_field_names) != 0);
275 /**************************************************************************//**
276 * Determine whether a name-value pair should be allowed (not suppressed).
278 * @param throttle_spec Throttle specification for the domain being encoded.
279 * @param field_name The field name holding the name-value pairs.
280 * @param name The name of the name-value pair to encoded or suppress.
281 * @return true if the name-value pair should be suppressed, false otherwise.
282 *****************************************************************************/
283 bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC * throttle_spec,
284 const char * const field_name,
285 const char * const name)
287 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
289 bool suppress = false;
293 /***************************************************************************/
294 /* Check preconditions. */
295 /***************************************************************************/
296 assert(field_name != NULL);
297 assert(name != NULL);
299 /***************************************************************************/
300 /* If the throttle spec and hash table exist, query the nv_pairs table. */
301 /***************************************************************************/
302 if ((throttle_spec != NULL) && (throttle_spec->hash_nv_pairs_list != NULL))
306 hash_query.key = (char * const) field_name;
307 hit = (hsearch_r(hash_query,
310 throttle_spec->hash_nv_pairs_list) != 0);
313 nv_pairs = hash_result->data;
317 /***************************************************************************/
318 /* If we got a hit, and the nv_pairs and hash table exist, query the */
319 /* nv_pairs table. */
320 /***************************************************************************/
321 if (hit && (nv_pairs != NULL) && (nv_pairs->hash_nv_pair_names != NULL))
325 hash_query.key = (char * const) name;
326 suppress = (hsearch_r(hash_query,
329 nv_pairs->hash_nv_pair_names) != 0);
337 /**************************************************************************//**
338 * Initialize event throttling to the default state.
340 * Called from ::evel_initialize.
341 *****************************************************************************/
342 void evel_throttle_initialize()
349 for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
351 evel_throttle_spec[ii] = NULL;
354 pthread_rc = pthread_mutex_init(&evel_measurement_interval_mutex, NULL);
355 assert(pthread_rc == 0);
357 evel_measurement_interval = EVEL_MEASUREMENT_INTERVAL_UKNOWN;
362 /**************************************************************************//**
363 * Clean up event throttling.
365 * Called from ::evel_terminate.
366 *****************************************************************************/
367 void evel_throttle_terminate()
374 for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
376 if (evel_throttle_spec[ii] != NULL)
378 evel_throttle_free(evel_throttle_spec[ii]);
379 evel_throttle_spec[ii] = NULL;
383 pthread_rc = pthread_mutex_destroy(&evel_measurement_interval_mutex);
384 assert(pthread_rc == 0);
389 /**************************************************************************//**
390 * Finalize a single ::EVEL_THROTTLE_SPEC.
392 * Now that the specification is collected, build hash tables to simplify the
395 * @param throttle_spec The ::EVEL_THROTTLE_SPEC to finalize.
396 *****************************************************************************/
397 void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec)
400 DLIST_ITEM * dlist_item;
405 /***************************************************************************/
406 /* Check preconditions. */
407 /***************************************************************************/
408 assert(throttle_spec != NULL);
410 /***************************************************************************/
411 /* Populate the hash table for suppressed field names. */
412 /***************************************************************************/
413 throttle_spec->hash_field_names =
414 evel_throttle_hash_create(&throttle_spec->suppressed_field_names);
416 /***************************************************************************/
417 /* Create the hash table for suppressed nv pairs. */
418 /***************************************************************************/
419 nv_pairs_count = dlist_count(&throttle_spec->suppressed_nv_pairs_list);
420 if (nv_pairs_count > 0)
422 throttle_spec->hash_nv_pairs_list = calloc(1, sizeof(struct hsearch_data));
423 assert(throttle_spec->hash_nv_pairs_list != NULL);
425 /*************************************************************************/
426 /* Provide plenty of space in the table - see hcreate_r notes. */
427 /*************************************************************************/
428 if (hcreate_r(nv_pairs_count * 2, throttle_spec->hash_nv_pairs_list) == 0)
430 EVEL_ERROR("Failed to create hash table");
431 free(throttle_spec->hash_nv_pairs_list);
432 throttle_spec->hash_nv_pairs_list = NULL;
436 /***************************************************************************/
437 /* Populate the hash tables under suppressed field names. */
438 /***************************************************************************/
439 dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
440 while (dlist_item != NULL)
442 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs = dlist_item->item;
445 /*************************************************************************/
446 /* Set the key to the string, and the item to the nv_pairs. */
447 /*************************************************************************/
448 assert(nv_pairs != NULL);
449 hash_add.key = nv_pairs->nv_pair_field_name;
450 hash_add.data = nv_pairs;
451 hsearch_r(hash_add, ENTER, &add_result, throttle_spec->hash_nv_pairs_list);
453 /*************************************************************************/
454 /* Create the nv_pair_names hash since we're in here. */
455 /*************************************************************************/
456 nv_pairs->hash_nv_pair_names =
457 evel_throttle_hash_create(&nv_pairs->suppressed_nv_pair_names);
459 dlist_item = dlist_get_next(dlist_item);
465 /**************************************************************************//**
466 * Create and populate a hash table from a DLIST of keys.
468 * @param hash_keys Pointer to a DLIST of hash table keys.
469 * @return Pointer to the created hash-table, or NULL on failure.
470 *****************************************************************************/
471 struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys)
474 struct hsearch_data * hash_table;
479 /***************************************************************************/
480 /* Check preconditions. */
481 /***************************************************************************/
482 assert(hash_keys != NULL);
484 /***************************************************************************/
485 /* Count the keys and if there are any, populate the hash table with them. */
486 /***************************************************************************/
487 key_count = dlist_count(hash_keys);
490 EVEL_DEBUG("Populating table for %d keys", key_count);
492 hash_table = calloc(1, sizeof(struct hsearch_data));
493 assert(hash_table != NULL);
495 /*************************************************************************/
496 /* We need to leave plenty of space in the table - see hcreate_r notes. */
497 /*************************************************************************/
498 if (hcreate_r(key_count * 2, hash_table) != 0)
500 DLIST_ITEM * dlist_item;
501 dlist_item = dlist_get_first(hash_keys);
502 while (dlist_item != NULL)
504 assert(dlist_item->item != NULL);
506 /*********************************************************************/
507 /* Set the key and data to the item, which is a string in this case. */
508 /*********************************************************************/
510 hash_add.key = dlist_item->item;
511 hash_add.data = dlist_item->item;
512 hsearch_r(hash_add, ENTER, &add_result, hash_table);
513 dlist_item = dlist_get_next(dlist_item);
518 EVEL_ERROR("Failed to create hash table");
533 /**************************************************************************//**
534 * Free resources associated with a single ::EVEL_THROTTLE_SPEC.
536 * @param throttle_spec The ::EVEL_THROTTLE_SPEC to free.
537 *****************************************************************************/
538 void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec)
541 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
545 /***************************************************************************/
546 /* Check preconditions. */
547 /***************************************************************************/
548 assert(throttle_spec != NULL);
550 /***************************************************************************/
551 /* Free any hash tables. */
552 /***************************************************************************/
553 if (throttle_spec->hash_field_names != NULL)
555 hdestroy_r(throttle_spec->hash_field_names);
556 free(throttle_spec->hash_field_names);
558 if (throttle_spec->hash_nv_pairs_list != NULL)
560 hdestroy_r(throttle_spec->hash_nv_pairs_list);
561 free(throttle_spec->hash_nv_pairs_list);
564 /***************************************************************************/
565 /* Iterate through the linked lists, freeing memory. */
566 /***************************************************************************/
567 field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
568 while (field_name != NULL)
571 field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
574 nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
575 while (nv_pairs != NULL)
577 evel_throttle_free_nv_pair(nv_pairs);
578 nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
586 /**************************************************************************//**
587 * Free resources associated with a single ::EVEL_SUPPRESSED_NV_PAIR.
589 * @param nv_pair The ::EVEL_SUPPRESSED_NV_PAIR to free.
590 *****************************************************************************/
591 void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
593 char * suppressed_name;
597 /***************************************************************************/
598 /* Check preconditions. */
599 /***************************************************************************/
600 assert(nv_pairs != NULL);
602 /***************************************************************************/
603 /* Free any hash tables. */
604 /***************************************************************************/
605 if (nv_pairs->hash_nv_pair_names != NULL)
607 hdestroy_r(nv_pairs->hash_nv_pair_names);
608 free(nv_pairs->hash_nv_pair_names);
611 /***************************************************************************/
612 /* Iterate through the linked lists, freeing memory. */
613 /***************************************************************************/
614 suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
615 while (suppressed_name != NULL)
617 free(suppressed_name);
618 suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
620 if (nv_pairs->nv_pair_field_name != NULL)
622 free(nv_pairs->nv_pair_field_name);
629 /**************************************************************************//**
630 * Handle a JSON response from the listener, as a list of tokens from JSMN.
632 * @param chunk Memory chunk containing the JSON buffer.
633 * @param json_tokens Array of tokens to handle.
634 * @param num_tokens The number of tokens to handle.
635 * @param post The memory chunk in which to place any resulting POST.
636 * @return true if the command was handled, false otherwise.
637 *****************************************************************************/
638 bool evel_handle_command_list(const MEMORY_CHUNK * const chunk,
639 const jsmntok_t * const json_tokens,
640 const int num_tokens,
641 MEMORY_CHUNK * const post)
643 EVEL_JSON_STACK stack;
644 EVEL_JSON_STACK * json_stack = &stack;
645 EVEL_JSON_STACK_ENTRY * entry;
652 /***************************************************************************/
653 /* Check preconditions. */
654 /***************************************************************************/
655 assert(chunk != NULL);
656 assert(json_tokens != NULL);
657 assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS);
659 /***************************************************************************/
660 /* Collect one top-level item. */
661 /***************************************************************************/
662 evel_init_json_stack(json_stack, chunk);
664 /***************************************************************************/
665 /* Initialize JSON processing variables. */
666 /***************************************************************************/
667 evel_provide_throttling_state = false;
668 evel_command_type_value = NULL;
669 evel_measurement_interval_value = NULL;
670 evel_throttle_spec_domain_value = NULL;
671 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
672 evel_temp_throttle = NULL;
673 evel_json_command_state = EVEL_JCS_START;
675 /***************************************************************************/
676 /* Loop through the tokens, keeping a stack of state representing the */
677 /* nested JSON structure (see json_state). We also track our way through */
678 /* the ::EVEL_JSON_COMMAND_STATE as we go. */
679 /***************************************************************************/
680 while (json_ok && (token_index < num_tokens))
682 const jsmntok_t * const token = &json_tokens[token_index];
686 evel_debug_token(chunk, token);
689 /*************************************************************************/
690 /* We may have popped or pushed, so always re-evaluate the stack entry. */
691 /*************************************************************************/
692 entry = &json_stack->entry[json_stack->level];
697 if ((entry->json_state == EVEL_JSON_ITEM) ||
698 (entry->json_state == EVEL_JSON_VALUE))
700 json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_KEY);
704 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
705 entry->json_state, token_index, token->type);
711 if ((entry->json_state == EVEL_JSON_ITEM) ||
712 (entry->json_state == EVEL_JSON_VALUE))
714 json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_ITEM);
718 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
719 entry->json_state, token_index, token->type);
725 if (entry->json_state == EVEL_JSON_KEY)
727 evel_stack_store_key(json_stack, token);
729 else if (entry->json_state == EVEL_JSON_VALUE)
731 evel_stack_store_value(json_stack, token);
733 else if (entry->json_state == EVEL_JSON_ITEM)
735 evel_stack_store_item(json_stack, token);
739 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
740 entry->json_state, token_index, token->type);
746 if (entry->json_state == EVEL_JSON_VALUE)
748 evel_stack_store_value(json_stack, token);
750 else if (entry->json_state == EVEL_JSON_ITEM)
752 evel_stack_store_item(json_stack, token);
756 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
757 entry->json_state, token_index, token->type);
764 EVEL_ERROR("Unexpected JSON format at token %d (%d)",
765 token_index, token->type);
770 /*************************************************************************/
771 /* Pop the stack if we're counted enough nested items. */
772 /*************************************************************************/
773 evel_stack_pop(json_stack);
778 /***************************************************************************/
779 /* Cleanup the stack - we may have exited without winding it back, if the */
780 /* input was not well formed. */
781 /***************************************************************************/
782 evel_stack_cleanup(json_stack);
784 /***************************************************************************/
785 /* We may want to generate and POST a response to the command list. */
786 /***************************************************************************/
789 evel_command_list_response(post);
792 /***************************************************************************/
793 /* Make sure we're clean on exit. */
794 /***************************************************************************/
795 assert(evel_command_type_value == NULL);
796 assert(evel_measurement_interval_value == NULL);
797 assert(evel_throttle_spec_domain_value == NULL);
798 assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
799 assert(evel_temp_throttle == NULL);
806 /**************************************************************************//**
807 * Copy a copy of an element, in string form.
809 * The caller must manage memory allocated for the copied string.
811 * @param chunk Memory chunk containing the JSON buffer.
812 * @param token The token to copy from.
813 * @return the copy of the element.
814 *****************************************************************************/
815 char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
816 const jsmntok_t * const token)
823 /***************************************************************************/
824 /* Call strdup to copy the string, inserting a temporary \0 for the call. */
825 /***************************************************************************/
826 temp_char = chunk->memory[token->end];
827 chunk->memory[token->end] = '\0';
828 result = strdup(chunk->memory + token->start);
829 assert(result != NULL);
830 chunk->memory[token->end] = temp_char;
837 /**************************************************************************//**
838 * Copy a copy of an element, in string form.
840 * @param json_stack The JSON stack to initialize.
841 * @param chunk The underlying memory chunk used for parsing.
842 *****************************************************************************/
843 void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
844 const MEMORY_CHUNK * const chunk)
846 EVEL_JSON_STACK_ENTRY * entry;
850 json_stack->level = 0;
851 entry = json_stack->entry;
852 entry->json_state = EVEL_JSON_ITEM;
853 entry->json_count = 0;
854 entry->num_required = 1;
855 entry->json_key = NULL;
856 json_stack->chunk = chunk;
861 /**************************************************************************//**
862 * Push a new entry on the stack
864 * @param json_stack The stack.
865 * @param num_required The number of elements required.
866 * @param new_state The state for the new entry.
867 * @return false if we cannot push onto the stack.
868 *****************************************************************************/
869 bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
870 const int num_required,
871 const EVEL_JSON_STATE new_state)
873 EVEL_JSON_STACK_ENTRY * entry;
879 /***************************************************************************/
880 /* Check preconditions. */
881 /***************************************************************************/
882 assert(json_stack != NULL);
883 assert(json_stack->level >= 0);
884 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
885 assert((new_state == EVEL_JSON_ITEM) || (new_state == EVEL_JSON_KEY));
887 /***************************************************************************/
888 /* Check nesting depth, and stop processing if we hit the limit. */
889 /***************************************************************************/
890 if ((json_stack->level + 1) >= EVEL_JSON_STACK_DEPTH)
892 EVEL_ERROR("JSON Nesting is too deep - stop processing");
897 /***************************************************************************/
898 /* Evaluate cases where we recurse and are interested in the contents. */
899 /***************************************************************************/
900 entry = &json_stack->entry[json_stack->level];
901 key = entry->json_key;
903 /***************************************************************************/
904 /* Note that this is the key before we drop a level. */
905 /***************************************************************************/
908 EVEL_DEBUG("Push with key: %s", key);
910 switch (evel_json_command_state)
913 if (strcmp(key, "commandList") == 0)
915 evel_set_command_state(EVEL_JCS_COMMAND_LIST);
919 case EVEL_JCS_COMMAND_LIST_ENTRY:
920 if (strcmp(key, "command") == 0)
923 evel_set_command_state(EVEL_JCS_COMMAND);
927 case EVEL_JCS_COMMAND:
928 if (strcmp(key, "eventDomainThrottleSpecification") == 0)
930 evel_open_throttle_spec();
931 evel_set_command_state(EVEL_JCS_SPEC);
936 if (strcmp(key, "suppressedFieldNames") == 0)
938 evel_set_command_state(EVEL_JCS_FIELD_NAMES);
940 else if (strcmp(key, "suppressedNvPairsList") == 0)
942 evel_set_command_state(EVEL_JCS_PAIRS_LIST);
946 case EVEL_JCS_PAIRS_LIST_ENTRY:
947 if (strcmp(key, "suppressedNvPairNames") == 0)
949 evel_set_command_state(EVEL_JCS_NV_PAIR_NAMES);
953 case EVEL_JCS_FIELD_NAMES:
954 case EVEL_JCS_PAIRS_LIST:
955 case EVEL_JCS_NV_PAIR_NAMES:
957 EVEL_ERROR("Unexpected JSON key %s in state %d",
959 evel_json_command_state);
965 EVEL_DEBUG("Push with no key");
967 /*************************************************************************/
968 /* If we're pushing without a key, then we're in an array. We switch */
969 /* state based on the existing state and stack level. */
970 /*************************************************************************/
971 const int COMMAND_LIST_LEVEL = 2;
972 const int NV_PAIRS_LIST_LEVEL = 6;
974 if ((evel_json_command_state == EVEL_JCS_PAIRS_LIST) &&
975 (json_stack->level == NV_PAIRS_LIST_LEVEL))
977 /***********************************************************************/
978 /* We are entering an object within the "suppressedNvPairsList" array. */
979 /***********************************************************************/
980 evel_open_nv_pairs_list_entry();
981 evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
984 if ((evel_json_command_state == EVEL_JCS_COMMAND_LIST) &&
985 (json_stack->level == COMMAND_LIST_LEVEL))
987 /***********************************************************************/
988 /* We are entering an object within the "commandList" array. */
989 /***********************************************************************/
990 evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
994 /***************************************************************************/
995 /* Push the stack and initialize the entry. */
996 /***************************************************************************/
999 EVEL_DEBUG("Stack Push -> %d", json_stack->level);
1000 entry = &json_stack->entry[json_stack->level];
1001 entry->json_count = 0;
1002 entry->num_required = num_required;
1003 entry->json_state = new_state;
1004 entry->json_key = NULL;
1014 /**************************************************************************//**
1015 * Pop any stack entries which have collected the required number of items.
1017 * @param json_stack The stack.
1018 *****************************************************************************/
1019 void evel_stack_pop(EVEL_JSON_STACK * const json_stack)
1021 EVEL_JSON_STACK_ENTRY * entry;
1026 /***************************************************************************/
1027 /* Check preconditions. */
1028 /***************************************************************************/
1029 assert(json_stack != NULL);
1030 assert(json_stack->level >= 0);
1031 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1033 entry = &json_stack->entry[json_stack->level];
1034 while ((json_stack->level > 0) && (entry->json_count == entry->num_required))
1036 key = entry->json_key;
1038 switch (evel_json_command_state)
1040 case EVEL_JCS_COMMAND_LIST:
1041 evel_set_command_state(EVEL_JCS_START);
1044 case EVEL_JCS_COMMAND_LIST_ENTRY:
1045 evel_set_command_state(EVEL_JCS_COMMAND_LIST);
1048 case EVEL_JCS_COMMAND:
1049 evel_close_command();
1050 evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
1054 evel_close_throttle_spec();
1055 evel_set_command_state(EVEL_JCS_COMMAND);
1058 case EVEL_JCS_FIELD_NAMES:
1059 evel_set_command_state(EVEL_JCS_SPEC);
1062 case EVEL_JCS_PAIRS_LIST:
1063 evel_set_command_state(EVEL_JCS_SPEC);
1066 case EVEL_JCS_PAIRS_LIST_ENTRY:
1067 evel_close_nv_pairs_list_entry();
1068 evel_set_command_state(EVEL_JCS_PAIRS_LIST);
1071 case EVEL_JCS_NV_PAIR_NAMES:
1072 evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
1079 /*************************************************************************/
1080 /* Free off any key that was duplicated and stored. */
1081 /*************************************************************************/
1085 entry->json_key = NULL;
1088 /*************************************************************************/
1089 /* We just reached the required number of key-value pairs or items, so */
1090 /* pop the stack. */
1091 /*************************************************************************/
1092 json_stack->level--;
1095 EVEL_DEBUG("Stack Pop -> %d", json_stack->level);
1097 /*************************************************************************/
1098 /* We just completed collection of an ITEM (within an ARRAY) or a VALUE */
1099 /* (within an OBJECT). Either way, we need to count it. */
1100 /*************************************************************************/
1101 entry->json_count++;
1103 /*************************************************************************/
1104 /* If we just completed a VALUE, then we expect the next element to be a */
1105 /* key, if there is a next element. */
1106 /*************************************************************************/
1107 if (entry->json_state == EVEL_JSON_VALUE)
1109 entry->json_state = EVEL_JSON_KEY;
1116 /**************************************************************************//**
1117 * Pop all stack entries, freeing any memory as we go.
1119 * @param json_stack The stack.
1120 *****************************************************************************/
1121 void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack)
1123 EVEL_JSON_STACK_ENTRY * entry;
1127 /***************************************************************************/
1128 /* Check preconditions. */
1129 /***************************************************************************/
1130 assert(json_stack != NULL);
1131 assert(json_stack->level >= 0);
1132 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1134 entry = &json_stack->entry[json_stack->level];
1135 while ((json_stack->level > 0))
1137 /*************************************************************************/
1138 /* Free off any key that was duplicated and stored. */
1139 /*************************************************************************/
1140 if (entry->json_key != NULL)
1142 free(entry->json_key);
1143 entry->json_key = NULL;
1146 /*************************************************************************/
1147 /* We just reached the required number of key-value pairs or items, so */
1148 /* pop the stack. */
1149 /*************************************************************************/
1150 json_stack->level--;
1154 /***************************************************************************/
1155 /* If we hit EVEL_JSON_STACK_DEPTH, we exit the loop and can leave these */
1156 /* values hanging - so clean them up. */
1157 /***************************************************************************/
1158 if (evel_command_type_value != NULL)
1160 free(evel_command_type_value);
1161 evel_command_type_value = NULL;
1163 if (evel_measurement_interval_value != NULL)
1165 free(evel_measurement_interval_value);
1166 evel_measurement_interval_value = NULL;
1168 if (evel_throttle_spec_domain_value != NULL)
1170 free(evel_throttle_spec_domain_value);
1171 evel_throttle_spec_domain_value = NULL;
1173 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1174 if (evel_temp_throttle != NULL)
1176 evel_throttle_free(evel_temp_throttle);
1177 evel_temp_throttle = NULL;
1183 /**************************************************************************//**
1184 * Store a key in the JSON stack.
1186 * We always store the most recent key at each level in the stack.
1188 * @param json_stack The stack.
1189 * @param token The token holding the key.
1190 *****************************************************************************/
1191 void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
1192 const jsmntok_t * const token)
1194 EVEL_JSON_STACK_ENTRY * entry;
1198 /***************************************************************************/
1199 /* Check preconditions. */
1200 /***************************************************************************/
1201 assert(json_stack != NULL);
1202 assert(json_stack->level >= 0);
1203 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1205 /***************************************************************************/
1206 /* Free any previously stored key, replacing it with the new one. */
1207 /***************************************************************************/
1208 entry = &json_stack->entry[json_stack->level];
1209 if (entry->json_key != NULL)
1211 free(entry->json_key);
1213 entry->json_key = evel_stack_strdup(json_stack->chunk, token);
1215 /***************************************************************************/
1216 /* Switch state to collecting the corresponding value. */
1217 /***************************************************************************/
1218 entry->json_state = EVEL_JSON_VALUE;
1220 EVEL_DEBUG("Stored key: %s", entry->json_key);
1224 /**************************************************************************//**
1225 * Store a value in the JSON stack.
1227 * @param json_stack The stack.
1228 * @param token The token holding the value.
1229 *****************************************************************************/
1230 void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
1231 const jsmntok_t * const token)
1233 EVEL_JSON_STACK_ENTRY * entry;
1239 /***************************************************************************/
1240 /* Check preconditions. */
1241 /***************************************************************************/
1242 assert(json_stack != NULL);
1243 assert(json_stack->level >= 0);
1244 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1246 /***************************************************************************/
1247 /* Based on the (key, state), work out whether we're expecting a value, */
1248 /* then store or ignore it as required. */
1249 /***************************************************************************/
1250 entry = &json_stack->entry[json_stack->level];
1251 value = evel_stack_strdup(json_stack->chunk, token);
1253 EVEL_DEBUG("Store value: %s", value);
1255 switch (evel_json_command_state)
1257 case EVEL_JCS_COMMAND:
1258 if (strcmp(entry->json_key, "commandType") == 0)
1260 evel_command_type_value = value;
1263 else if (strcmp(entry->json_key, "measurementInterval") == 0)
1265 evel_measurement_interval_value = value;
1271 if (strcmp(entry->json_key, "eventDomain") == 0)
1273 evel_throttle_spec_domain_value = value;
1278 case EVEL_JCS_PAIRS_LIST_ENTRY:
1279 if (strcmp(entry->json_key, "nvPairFieldName") == 0)
1281 evel_store_nv_pair_field_name(value);
1287 EVEL_DEBUG("Ignoring value in state: %s",
1288 evel_jcs_strings[evel_json_command_state]);
1294 EVEL_DEBUG("Ignored value: %s", value);
1298 /***************************************************************************/
1299 /* Switch state to another key. */
1300 /***************************************************************************/
1301 entry->json_state = EVEL_JSON_KEY;
1303 /***************************************************************************/
1304 /* Count the key-value pair. */
1305 /***************************************************************************/
1306 entry->json_count++;
1311 /**************************************************************************//**
1312 * Store an item in the JSON stack - a string or primitive in an array.
1314 * @param json_stack The stack.
1315 * @param token The token holding the item.
1316 *****************************************************************************/
1317 void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
1318 const jsmntok_t * const token)
1320 EVEL_JSON_STACK_ENTRY * entry;
1326 /***************************************************************************/
1327 /* Check preconditions. */
1328 /***************************************************************************/
1329 assert(json_stack != NULL);
1330 assert(json_stack->level >= 0);
1331 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1333 /***************************************************************************/
1334 /* Based on the state, work out whether we're expecting an item, then */
1335 /* store or ignore it as required. */
1336 /***************************************************************************/
1337 entry = &json_stack->entry[json_stack->level];
1338 item = evel_stack_strdup(json_stack->chunk, token);
1340 EVEL_DEBUG("Store item: %s", item);
1342 switch (evel_json_command_state)
1344 case EVEL_JCS_NV_PAIR_NAMES:
1345 evel_store_nv_pair_name(item);
1349 case EVEL_JCS_FIELD_NAMES:
1350 evel_store_suppressed_field_name(item);
1355 EVEL_DEBUG("Ignoring item in state: %s",
1356 evel_jcs_strings[evel_json_command_state]);
1362 EVEL_DEBUG("Ignored item: %s", item);
1366 /***************************************************************************/
1367 /* We need another item. This is purely defensive. */
1368 /***************************************************************************/
1369 entry->json_state = EVEL_JSON_ITEM;
1371 /***************************************************************************/
1372 /* Count the item. */
1373 /***************************************************************************/
1374 entry->json_count++;
1377 /**************************************************************************//**
1378 * Set the JSON command state to a new value.
1380 * @param new_state The new state to set.
1381 *****************************************************************************/
1382 void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state)
1386 /***************************************************************************/
1387 /* Check preconditions. */
1388 /***************************************************************************/
1389 assert(evel_json_command_state < EVEL_JCS_MAX);
1390 assert(new_state < EVEL_JCS_MAX);
1392 /***************************************************************************/
1393 /* Provide common debug, and set the new state. */
1394 /***************************************************************************/
1395 EVEL_DEBUG("Command State: %s -> %s",
1396 evel_jcs_strings[evel_json_command_state],
1397 evel_jcs_strings[new_state]);
1398 evel_json_command_state = new_state;
1403 /**************************************************************************//**
1404 * Produce debug output from a JSON token.
1406 * @param chunk Memory chunk containing the JSON buffer.
1407 * @param token Token to dump.
1408 *****************************************************************************/
1409 void evel_debug_token(const MEMORY_CHUNK * const chunk,
1410 const jsmntok_t * const token)
1416 /***************************************************************************/
1417 /* Check preconditions. */
1418 /***************************************************************************/
1419 assert(token->type > 0);
1420 assert(token->type < JSON_TOKEN_TYPES);
1422 /***************************************************************************/
1423 /* Log the token, leaving it in the state in which it started. */
1424 /***************************************************************************/
1425 temp_char = chunk->memory[token->end];
1426 chunk->memory[token->end] = '\0';
1427 EVEL_DEBUG("JSON token type: %s", evel_json_token_strings[token->type]);
1428 EVEL_DEBUG("JSON token: %s", chunk->memory + token->start);
1429 chunk->memory[token->end] = temp_char;
1434 /**************************************************************************//**
1435 * Post a response to the commandList.
1437 * @param post Memory chunk in which to post a response.
1438 *****************************************************************************/
1439 void evel_command_list_response(MEMORY_CHUNK * const post)
1445 /***************************************************************************/
1446 /* Check preconditions. */
1447 /***************************************************************************/
1448 assert(post != NULL);
1449 assert(post->memory == NULL);
1451 if (evel_provide_throttling_state)
1453 EVEL_DEBUG("Provide throttling state");
1455 /*************************************************************************/
1456 /* Encode the response, making it printf-able for debug. */
1457 /*************************************************************************/
1458 json_post = malloc(EVEL_MAX_JSON_BODY);
1459 assert(json_post != NULL);
1460 post->size = evel_json_encode_throttle(json_post, EVEL_MAX_JSON_BODY - 1);
1461 post->memory = json_post;
1462 post->memory[post->size] = '\0';
1463 evel_provide_throttling_state = false;
1469 /**************************************************************************//**
1470 * Encode the full throttling specification according to AT&T's schema.
1472 * @param json Pointer to where to store the JSON encoded data.
1473 * @param max_size Size of storage available in json_body.
1474 * @returns Number of bytes actually written.
1475 *****************************************************************************/
1476 int evel_json_encode_throttle(char * const json, const int max_size)
1485 /***************************************************************************/
1486 /* Check preconditions. */
1487 /***************************************************************************/
1488 assert(json != NULL);
1489 assert(max_size > 0);
1491 /***************************************************************************/
1492 /* Work out if we're throttled. */
1493 /***************************************************************************/
1495 for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1497 if (evel_throttle_spec[domain] != NULL)
1503 /***************************************************************************/
1504 /* Encode the response. */
1505 /***************************************************************************/
1507 offset += snprintf(json + offset, max_size - offset,
1508 "{\"eventThrottlingState\": {");
1509 offset += snprintf(json + offset, max_size - offset,
1510 "\"eventThrottlingMode\": \"%s\"",
1511 throttled ? "throttled" : "normal");
1514 offset += snprintf(json + offset, max_size - offset,
1515 ", \"eventDomainThrottleSpecificationList\": [");
1517 domain_added = false;
1518 for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1520 if (evel_throttle_spec[domain] != NULL)
1524 offset += snprintf(json + offset, max_size - offset, ", ");
1527 offset += evel_json_encode_throttle_spec(json + offset,
1530 domain_added = true;
1534 offset += snprintf(json + offset, max_size - offset, "]");
1537 offset += snprintf(json + offset, max_size - offset, "}}");
1544 /**************************************************************************//**
1545 * Encode a throttling specification for a domain.
1547 * @param json Pointer to where to store the JSON encoded data.
1548 * @param max_size Size of storage available in json_body.
1549 * @returns Number of bytes actually written.
1550 *****************************************************************************/
1551 int evel_json_encode_throttle_spec(char * const json,
1553 const EVEL_EVENT_DOMAINS domain)
1556 EVEL_THROTTLE_SPEC * throttle_spec;
1557 DLIST_ITEM * dlist_item;
1560 /***************************************************************************/
1561 /* Check preconditions. */
1562 /***************************************************************************/
1563 assert(domain >= EVEL_DOMAIN_FAULT);
1564 assert(domain < EVEL_MAX_DOMAINS);
1565 assert(evel_throttle_spec[domain] != NULL);
1567 throttle_spec = evel_throttle_spec[domain];
1569 /***************************************************************************/
1570 /* Encode the domain. */
1571 /***************************************************************************/
1573 offset += snprintf(json + offset, max_size - offset,
1575 offset += snprintf(json + offset, max_size - offset,
1576 "\"eventDomain\": \"%s\"",
1577 evel_domain_strings[domain]);
1579 /***************************************************************************/
1580 /* Encode "suppressedFieldNames". */
1581 /***************************************************************************/
1582 dlist_item = dlist_get_first(&throttle_spec->suppressed_field_names);
1583 if (dlist_item != NULL)
1585 offset += snprintf(json + offset, max_size - offset,
1586 ", \"suppressedFieldNames\": [");
1587 while (dlist_item != NULL)
1589 char * suppressed_field = dlist_item->item;
1590 assert(suppressed_field != NULL);
1592 offset += snprintf(json + offset, max_size - offset,
1593 "\"%s\"", suppressed_field);
1594 dlist_item = dlist_get_next(dlist_item);
1595 if (dlist_item != NULL)
1597 offset += snprintf(json + offset, max_size - offset, ", ");
1601 offset += snprintf(json + offset, max_size - offset, "]");
1604 /***************************************************************************/
1605 /* Encode "suppressedNvPairsList". */
1606 /***************************************************************************/
1607 dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
1608 if (dlist_item != NULL)
1610 offset += snprintf(json + offset, max_size - offset,
1611 ", \"suppressedNvPairsList\": [");
1612 while (dlist_item != NULL)
1614 offset += evel_json_encode_nv_pairs(json + offset,
1617 dlist_item = dlist_get_next(dlist_item);
1618 if (dlist_item != NULL)
1620 offset += snprintf(json + offset, max_size - offset, ", ");
1624 offset += snprintf(json + offset, max_size - offset, "]");
1627 offset += snprintf(json + offset, max_size - offset, "}");
1634 /**************************************************************************//**
1635 * Encode a single "suppressedNvPairsListEntry".
1637 * @param json Pointer to where to store the JSON encoded data.
1638 * @param max_size Size of storage available in json_body.
1639 * @returns Number of bytes actually written.
1640 *****************************************************************************/
1641 int evel_json_encode_nv_pairs(char * const json,
1643 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
1645 DLIST_ITEM * dlist_item;
1649 /***************************************************************************/
1650 /* Check preconditions. */
1651 /***************************************************************************/
1652 assert(nv_pairs != NULL);
1653 assert(nv_pairs->nv_pair_field_name != NULL);
1654 assert(!dlist_is_empty(&nv_pairs->suppressed_nv_pair_names));
1656 /***************************************************************************/
1658 /***************************************************************************/
1660 offset += snprintf(json + offset, max_size - offset, "{");
1661 offset += snprintf(json + offset, max_size - offset,
1662 "\"nvPairFieldName\": \"%s\"",
1663 nv_pairs->nv_pair_field_name);
1664 dlist_item = dlist_get_first(&nv_pairs->suppressed_nv_pair_names);
1665 offset += snprintf(json + offset, max_size - offset,
1666 ", \"suppressedNvPairNames\": [");
1667 while (dlist_item != NULL)
1669 name = dlist_item->item;
1670 assert(name != NULL);
1671 offset += snprintf(json + offset, max_size - offset, "\"%s\"", name);
1672 dlist_item = dlist_get_next(dlist_item);
1673 if (dlist_item != NULL)
1675 offset += snprintf(json + offset, max_size - offset, ", ");
1678 offset += snprintf(json + offset, max_size - offset, "]");
1679 offset += snprintf(json + offset, max_size - offset, "}");
1686 /**************************************************************************//**
1687 * Method called when we open a "command" object.
1688 *****************************************************************************/
1689 void evel_open_command()
1693 /***************************************************************************/
1694 /* Make some assertions. */
1695 /***************************************************************************/
1696 assert(evel_command_type_value == NULL);
1697 assert(evel_measurement_interval_value == NULL);
1702 /**************************************************************************//**
1703 * Method called when we close a "command" object.
1704 *****************************************************************************/
1705 void evel_close_command()
1709 /***************************************************************************/
1710 /* If a commandType was provided, fan out and handle it now what we have */
1711 /* fathered all related information. */
1713 /* Note that we handle throttling specification and measurement interval */
1714 /* updates immediately on closing the command (not the list). We could */
1715 /* reject *all* commands in a list if any of them are invalid, but we are */
1716 /* take a best-effort strategy here - any valid-looking command gets */
1717 /* implemented regardless of what follows. */
1718 /***************************************************************************/
1719 if (evel_command_type_value != NULL)
1721 EVEL_DEBUG("Closing command %s", evel_command_type_value);
1723 if (strcmp(evel_command_type_value, "provideThrottlingState") == 0)
1725 evel_provide_throttling_state = true;
1727 else if (strcmp(evel_command_type_value, "throttlingSpecification") == 0)
1729 evel_set_throttling_spec();
1731 else if (strcmp(evel_command_type_value, "measurementIntervalChange") == 0)
1733 evel_set_measurement_interval();
1737 EVEL_ERROR("Ignoring unknown commandType: %s\n",
1738 evel_command_type_value);
1741 /*************************************************************************/
1742 /* Free the captured "commandType" value. */
1743 /*************************************************************************/
1744 free(evel_command_type_value);
1745 evel_command_type_value = NULL;
1748 /***************************************************************************/
1749 /* There could be an unused working throttle spec at this point - if the */
1750 /* "throttlingSpecification" commandType was not provided, or an invalid */
1751 /* domain was provided, or was not provided at all. */
1752 /***************************************************************************/
1753 if (evel_temp_throttle != NULL)
1755 evel_throttle_free(evel_temp_throttle);
1756 evel_temp_throttle = NULL;
1759 /***************************************************************************/
1760 /* Similarly, the domain could be set. */
1761 /***************************************************************************/
1762 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1764 /***************************************************************************/
1765 /* There could be an unused measurement interval value at this point - if */
1766 /* the "measurementIntervalChange" command was not provided. */
1767 /***************************************************************************/
1768 if (evel_measurement_interval_value != NULL)
1770 free(evel_measurement_interval_value);
1771 evel_measurement_interval_value = NULL;
1777 /**************************************************************************//**
1778 * Set the provided throttling specification, when the command closes.
1779 *****************************************************************************/
1780 void evel_set_throttling_spec()
1784 if ((evel_throttle_spec_domain >= 0) &&
1785 (evel_throttle_spec_domain < EVEL_MAX_DOMAINS))
1787 EVEL_DEBUG("Updating throttle spec for domain: %s",
1788 evel_domain_strings[evel_throttle_spec_domain]);
1790 /*************************************************************************/
1791 /* Free off the previous throttle specification for the domain, if there */
1793 /*************************************************************************/
1794 if (evel_throttle_spec[evel_throttle_spec_domain] != NULL)
1796 evel_throttle_free(evel_throttle_spec[evel_throttle_spec_domain]);
1799 /*************************************************************************/
1800 /* Finalize the working throttling spec, if there is one. */
1801 /*************************************************************************/
1802 if (evel_temp_throttle != NULL)
1804 evel_throttle_finalize(evel_temp_throttle);
1807 /*************************************************************************/
1808 /* Replace the throttle specification for the domain with the working */
1809 /* throttle specification. This could be NULL, if an empty throttle */
1810 /* specification has been received for a domain. */
1811 /*************************************************************************/
1812 evel_throttle_spec[evel_throttle_spec_domain] = evel_temp_throttle;
1813 evel_temp_throttle = NULL;
1819 /**************************************************************************//**
1820 * Set the provided measurement interval, when the command closes.
1821 *****************************************************************************/
1822 void evel_set_measurement_interval()
1826 if (evel_measurement_interval_value != NULL)
1828 const long int value = strtol(evel_measurement_interval_value, NULL, 10);
1830 if ((value >= 0) && (value <= INT_MAX))
1832 /***********************************************************************/
1833 /* Lock, update, unlock. */
1834 /***********************************************************************/
1835 EVEL_DEBUG("Updating measurement interval to %d\n", value);
1837 pthread_mutex_lock(&evel_measurement_interval_mutex);
1838 evel_measurement_interval = value;
1839 pthread_mutex_unlock(&evel_measurement_interval_mutex);
1843 EVEL_ERROR("Ignoring invalid measurement interval: %s",
1844 evel_measurement_interval_value);
1851 /**************************************************************************//**
1852 * Method called when we open an "eventDomainThrottleSpecification" object.
1853 *****************************************************************************/
1854 void evel_open_throttle_spec()
1858 /***************************************************************************/
1859 /* Check preconditions. */
1860 /***************************************************************************/
1861 assert(evel_throttle_spec_domain_value == NULL);
1862 assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
1863 assert(evel_temp_throttle == NULL);
1865 /***************************************************************************/
1866 /* Allocate and initialize an ::EVEL_THROTTLE_SPEC in which to hold */
1867 /* captured JSON elements. */
1868 /***************************************************************************/
1869 evel_temp_throttle = malloc(sizeof(EVEL_THROTTLE_SPEC));
1870 assert(evel_temp_throttle != NULL);
1871 dlist_initialize(&evel_temp_throttle->suppressed_field_names);
1872 dlist_initialize(&evel_temp_throttle->suppressed_nv_pairs_list);
1873 evel_temp_throttle->hash_field_names = NULL;
1874 evel_temp_throttle->hash_nv_pairs_list = NULL;
1879 /**************************************************************************//**
1880 * Method called when we close an "eventDomainThrottleSpecification" object.
1881 *****************************************************************************/
1882 void evel_close_throttle_spec()
1886 /***************************************************************************/
1887 /* Decode, free and blank a captured event domain value. */
1888 /***************************************************************************/
1889 if (evel_throttle_spec_domain_value != NULL)
1891 evel_throttle_spec_domain =
1892 evel_decode_domain(evel_throttle_spec_domain_value);
1893 free(evel_throttle_spec_domain_value);
1894 evel_throttle_spec_domain_value = NULL;
1897 /***************************************************************************/
1898 /* Free off an empty working throttle spec, to stop it being used. This */
1899 /* state should be represented by a NULL pointer for the domain. */
1900 /***************************************************************************/
1901 if (evel_temp_throttle != NULL)
1903 if (dlist_is_empty(&evel_temp_throttle->suppressed_field_names) &&
1904 dlist_is_empty(&evel_temp_throttle->suppressed_nv_pairs_list))
1906 free(evel_temp_throttle);
1907 evel_temp_throttle = NULL;
1914 /**************************************************************************//**
1915 * Convert a value for an "eventDomain" into an ::EVEL_EVENT_DOMAINS.
1917 * @param domain_value The domain string value to decode.
1918 * @returns The matching ::EVEL_EVENT_DOMAINS, or ::EVEL_MAX_DOMAINS on error.
1919 *****************************************************************************/
1920 EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value)
1922 EVEL_EVENT_DOMAINS result;
1927 /***************************************************************************/
1928 /* Check preconditions. */
1929 /***************************************************************************/
1930 assert(domain_value != NULL);
1932 result = EVEL_MAX_DOMAINS;
1933 for (ii = EVEL_DOMAIN_FAULT; ii < EVEL_MAX_DOMAINS; ii++)
1935 assert(evel_domain_strings[ii] != NULL);
1936 if (strcmp(evel_domain_strings[ii], domain_value) == 0)
1947 /**************************************************************************//**
1948 * Method called when we open a "suppressedNvPairsListEntry" object.
1949 *****************************************************************************/
1950 void evel_open_nv_pairs_list_entry()
1952 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1956 /***************************************************************************/
1957 /* Check preconditions. */
1958 /***************************************************************************/
1959 assert(evel_temp_throttle != NULL);
1961 /***************************************************************************/
1962 /* Allocate and initialize an ::EVEL_SUPPRESSED_NV_PAIRS, and add it to */
1964 /***************************************************************************/
1965 nv_pairs = malloc(sizeof(EVEL_SUPPRESSED_NV_PAIRS));
1966 assert(nv_pairs != NULL);
1967 nv_pairs->nv_pair_field_name = NULL;
1968 dlist_initialize(&nv_pairs->suppressed_nv_pair_names);
1969 nv_pairs->hash_nv_pair_names = NULL;
1970 dlist_push_last(&evel_temp_throttle->suppressed_nv_pairs_list, nv_pairs);
1975 /**************************************************************************//**
1976 * Method called when we close a "suppressedNvPairsListEntry" object.
1977 *****************************************************************************/
1978 void evel_close_nv_pairs_list_entry()
1980 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1981 EVEL_SUPPRESSED_NV_PAIRS * popped;
1985 /***************************************************************************/
1986 /* Get the latest nv pairs. This also performs the required checks. */
1987 /***************************************************************************/
1988 nv_pairs = evel_get_last_nv_pairs();
1990 /***************************************************************************/
1991 /* For a "suppressedNvPairsListEntry" to have any meaning, we need both */
1992 /* "nvPairFieldName" and "suppressedNvPairNames". If we don't, then pop */
1993 /* and free whatever we just collected. */
1994 /***************************************************************************/
1995 if ((nv_pairs->nv_pair_field_name == NULL) ||
1996 dlist_is_empty(&nv_pairs->suppressed_nv_pair_names))
1998 popped = dlist_pop_last(&evel_temp_throttle->suppressed_nv_pairs_list);
1999 assert(popped == nv_pairs);
2000 evel_throttle_free_nv_pair(popped);
2006 /**************************************************************************//**
2007 * Store an "nvPairFieldName" value in the working throttle spec.
2009 * @param value The value to store.
2010 *****************************************************************************/
2011 void evel_store_nv_pair_field_name(char * const value)
2013 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2017 /***************************************************************************/
2018 /* Get the latest nv pairs. This also performs the required checks. */
2019 /***************************************************************************/
2020 nv_pairs = evel_get_last_nv_pairs();
2022 /***************************************************************************/
2023 /* Store the value. */
2024 /***************************************************************************/
2025 nv_pairs->nv_pair_field_name = value;
2030 /**************************************************************************//**
2031 * Store a "suppressedNvPairNames" item in the working throttle spec.
2033 * @param item The item to store.
2034 *****************************************************************************/
2035 void evel_store_nv_pair_name(char * const item)
2037 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2041 /***************************************************************************/
2042 /* Get the latest nv pairs. This also performs the required checks. */
2043 /***************************************************************************/
2044 nv_pairs = evel_get_last_nv_pairs();
2046 /***************************************************************************/
2047 /* Store the item. */
2048 /***************************************************************************/
2049 dlist_push_last(&nv_pairs->suppressed_nv_pair_names, item);
2054 /**************************************************************************//**
2055 * Store a "suppressedFieldNames" item in the working throttle spec.
2057 * @param item The item to store.
2058 *****************************************************************************/
2059 void evel_store_suppressed_field_name(char * const item)
2063 /***************************************************************************/
2064 /* Check preconditions. */
2065 /***************************************************************************/
2066 assert(evel_temp_throttle != NULL);
2068 /***************************************************************************/
2069 /* Store the item. */
2070 /***************************************************************************/
2071 dlist_push_last(&evel_temp_throttle->suppressed_field_names, item);
2076 /**************************************************************************//**
2077 * Get the last added suppressed nv pairs list entry in the working spec.
2079 * @returns The last entry.
2080 *****************************************************************************/
2081 EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs()
2083 DLIST_ITEM * dlist_item;
2084 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2088 /***************************************************************************/
2089 /* Check preconditions. */
2090 /***************************************************************************/
2091 assert(evel_temp_throttle != NULL);
2093 /***************************************************************************/
2094 /* Get the pair that was added when we opened the list entry. */
2095 /***************************************************************************/
2096 dlist_item = dlist_get_last(&evel_temp_throttle->suppressed_nv_pairs_list);
2097 assert(dlist_item != NULL);
2098 nv_pairs = dlist_item->item;
2099 assert(nv_pairs != NULL);