1 /**************************************************************************//**
5 * Simple event manager that is responsible for taking events (Heartbeats,
6 * Faults and Measurements) from the ring-buffer and posting them to the API.
11 * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
16 * 1. Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement: This product includes
23 * software developed by the AT&T.
24 * 4. Neither the name of AT&T nor the names of its contributors may be used to
25 * endorse or promote products derived from this software without specific
26 * prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
29 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31 * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 *****************************************************************************/
48 #include "evel_throttle.h"
50 /*****************************************************************************/
51 /* The Event Throttling State for all domains, indexed by */
52 /* ::EVEL_EVENT_DOMAINS, corresponding to JSON eventDomain. */
54 /* A given domain is in a throttled state if ::evel_throttle_spec is */
56 /*****************************************************************************/
57 static EVEL_THROTTLE_SPEC * evel_throttle_spec[EVEL_MAX_DOMAINS];
59 /*****************************************************************************/
60 /* The current measurement interval. Default: MEASUREMENT_INTERVAL_UKNOWN. */
61 /* Must be protected by evel_measurement_interval_mutex. */
62 /*****************************************************************************/
63 static int evel_measurement_interval;
65 /*****************************************************************************/
66 /* Mutex protecting evel_measurement_interval from contention between an */
67 /* EVEL client reading it, and the EVEL event handler updating it. */
68 /*****************************************************************************/
69 static pthread_mutex_t evel_measurement_interval_mutex;
71 /*****************************************************************************/
72 /* Flag stating that we have received a "provideThrottlingState" command. */
73 /* Set during JSON processing and cleared on sending the throttling state. */
74 /*****************************************************************************/
75 static bool evel_provide_throttling_state;
77 /*****************************************************************************/
78 /* Holder for the "commandType" value during JSON processing. */
79 /*****************************************************************************/
80 static char * evel_command_type_value;
82 /*****************************************************************************/
83 /* Holder for the "measurementInterval" value during JSON processing. */
84 /*****************************************************************************/
85 static char * evel_measurement_interval_value;
87 /*****************************************************************************/
88 /* Holder for the "eventDomain" value during JSON processing. */
89 /*****************************************************************************/
90 static char * evel_throttle_spec_domain_value;
92 /*****************************************************************************/
93 /* Decoded version of ::evel_throttle_spec_domain_value. */
94 /*****************************************************************************/
95 static EVEL_EVENT_DOMAINS evel_throttle_spec_domain;
97 /*****************************************************************************/
98 /* During JSON processing of a single throttling specification, we collect */
99 /* parameters in this working ::EVEL_THROTTLE_SPEC */
100 /*****************************************************************************/
101 static EVEL_THROTTLE_SPEC * evel_temp_throttle;
103 /*****************************************************************************/
104 /* State tracking our progress through the command list */
105 /*****************************************************************************/
106 EVEL_JSON_COMMAND_STATE evel_json_command_state;
108 /*****************************************************************************/
109 /* Debug strings for ::EVEL_JSON_COMMAND_STATE. */
110 /*****************************************************************************/
111 static const char * const evel_jcs_strings[EVEL_JCS_MAX] = {
113 "EVEL_JCS_COMMAND_LIST",
114 "EVEL_JCS_COMMAND_LIST_ENTRY",
117 "EVEL_JCS_FIELD_NAMES",
118 "EVEL_JCS_PAIRS_LIST",
119 "EVEL_JCS_PAIRS_LIST_ENTRY",
120 "EVEL_JCS_NV_PAIR_NAMES"
123 /*****************************************************************************/
124 /* Debug strings for JSON token type. */
125 /*****************************************************************************/
126 #define JSON_TOKEN_TYPES (JSMN_PRIMITIVE + 1)
127 static const char * const evel_json_token_strings[JSON_TOKEN_TYPES] = {
135 /*****************************************************************************/
136 /* Debug strings for JSON domains. */
137 /*****************************************************************************/
138 static const char * evel_domain_strings[EVEL_MAX_DOMAINS] = {
142 "measurementsForVfScaling",
154 /*****************************************************************************/
155 /* Local prototypes. */
156 /*****************************************************************************/
157 static void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec);
158 static struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys);
159 static void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec);
160 static void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
161 static void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
162 const MEMORY_CHUNK * const chunk);
163 static bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
164 const int num_required,
165 const EVEL_JSON_STATE new_state);
166 static void evel_stack_pop(EVEL_JSON_STACK * const json_stack);
167 static void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack);
168 static char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
169 const jsmntok_t * const token);
170 static void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
171 const jsmntok_t * const token);
172 static void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
173 const jsmntok_t * const token);
174 static void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
175 const jsmntok_t * const token);
176 static void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state);
177 static void evel_debug_token(const MEMORY_CHUNK * const chunk,
178 const jsmntok_t * const token);
179 static void evel_command_list_response(MEMORY_CHUNK * const post);
180 static int evel_json_encode_throttle(char * const json, const int max_size);
181 static int evel_json_encode_throttle_spec(char * const json,
183 const EVEL_EVENT_DOMAINS domain);
184 static int evel_json_encode_nv_pairs(char * const json,
186 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
187 static void evel_close_command();
188 static void evel_open_command();
189 static void evel_set_throttling_spec();
190 static void evel_set_measurement_interval();
191 static void evel_open_throttle_spec();
192 static void evel_close_throttle_spec();
193 static EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value);
194 static void evel_open_nv_pairs_list_entry();
195 static void evel_close_nv_pairs_list_entry();
196 static void evel_store_nv_pair_field_name(char * const value);
197 static void evel_store_nv_pair_name(char * const item);
198 static void evel_store_suppressed_field_name(char * const item);
199 static EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs();
201 /**************************************************************************//**
202 * Return the current measurement interval provided by the Event Listener.
204 * @returns The current measurement interval
205 * @retval EVEL_MEASUREMENT_INTERVAL_UKNOWN (0) - interval has not been
207 *****************************************************************************/
208 int evel_get_measurement_interval()
214 /***************************************************************************/
215 /* Lock, read, unlock. */
216 /***************************************************************************/
217 pthread_mutex_lock(&evel_measurement_interval_mutex);
218 result = evel_measurement_interval;
219 pthread_mutex_unlock(&evel_measurement_interval_mutex);
226 /**************************************************************************//**
227 * Return the ::EVEL_THROTTLE_SPEC for a given domain.
229 * @param domain The domain for which to return state.
230 *****************************************************************************/
231 EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain)
233 EVEL_THROTTLE_SPEC * result;
237 /***************************************************************************/
238 /* Check preconditions. */
239 /***************************************************************************/
240 assert(domain < EVEL_MAX_DOMAINS);
242 result = evel_throttle_spec[domain];
249 /**************************************************************************//**
250 * Determine whether a field_name should be suppressed.
252 * @param throttle_spec Throttle specification for the domain being encoded.
253 * @param field_name The field name to encoded or suppress.
254 * @return true if the field_name should be suppressed, false otherwise.
255 *****************************************************************************/
256 bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC * throttle_spec,
257 const char * const field_name)
259 bool suppress = false;
263 /***************************************************************************/
264 /* Check preconditions. */
265 /***************************************************************************/
266 assert(field_name != NULL);
268 /***************************************************************************/
269 /* If the throttle spec and hash table exist, query the field_names table. */
270 /***************************************************************************/
271 if ((throttle_spec != NULL) && (throttle_spec->hash_field_names != NULL))
275 hash_query.key = (char * const) field_name;
276 suppress = (hsearch_r(hash_query,
279 throttle_spec->hash_field_names) != 0);
287 /**************************************************************************//**
288 * Determine whether a name-value pair should be allowed (not suppressed).
290 * @param throttle_spec Throttle specification for the domain being encoded.
291 * @param field_name The field name holding the name-value pairs.
292 * @param name The name of the name-value pair to encoded or suppress.
293 * @return true if the name-value pair should be suppressed, false otherwise.
294 *****************************************************************************/
295 bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC * throttle_spec,
296 const char * const field_name,
297 const char * const name)
299 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
301 bool suppress = false;
305 /***************************************************************************/
306 /* Check preconditions. */
307 /***************************************************************************/
308 assert(field_name != NULL);
309 assert(name != NULL);
311 /***************************************************************************/
312 /* If the throttle spec and hash table exist, query the nv_pairs table. */
313 /***************************************************************************/
314 if ((throttle_spec != NULL) && (throttle_spec->hash_nv_pairs_list != NULL))
318 hash_query.key = (char * const) field_name;
319 hit = (hsearch_r(hash_query,
322 throttle_spec->hash_nv_pairs_list) != 0);
325 nv_pairs = hash_result->data;
329 /***************************************************************************/
330 /* If we got a hit, and the nv_pairs and hash table exist, query the */
331 /* nv_pairs table. */
332 /***************************************************************************/
333 if (hit && (nv_pairs != NULL) && (nv_pairs->hash_nv_pair_names != NULL))
337 hash_query.key = (char * const) name;
338 suppress = (hsearch_r(hash_query,
341 nv_pairs->hash_nv_pair_names) != 0);
349 /**************************************************************************//**
350 * Initialize event throttling to the default state.
352 * Called from ::evel_initialize.
353 *****************************************************************************/
354 void evel_throttle_initialize()
361 for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
363 evel_throttle_spec[ii] = NULL;
366 pthread_rc = pthread_mutex_init(&evel_measurement_interval_mutex, NULL);
367 assert(pthread_rc == 0);
369 evel_measurement_interval = EVEL_MEASUREMENT_INTERVAL_UKNOWN;
374 /**************************************************************************//**
375 * Clean up event throttling.
377 * Called from ::evel_terminate.
378 *****************************************************************************/
379 void evel_throttle_terminate()
386 for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
388 if (evel_throttle_spec[ii] != NULL)
390 evel_throttle_free(evel_throttle_spec[ii]);
391 evel_throttle_spec[ii] = NULL;
395 pthread_rc = pthread_mutex_destroy(&evel_measurement_interval_mutex);
396 assert(pthread_rc == 0);
401 /**************************************************************************//**
402 * Finalize a single ::EVEL_THROTTLE_SPEC.
404 * Now that the specification is collected, build hash tables to simplify the
407 * @param throttle_spec The ::EVEL_THROTTLE_SPEC to finalize.
408 *****************************************************************************/
409 void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec)
412 DLIST_ITEM * dlist_item;
417 /***************************************************************************/
418 /* Check preconditions. */
419 /***************************************************************************/
420 assert(throttle_spec != NULL);
422 /***************************************************************************/
423 /* Populate the hash table for suppressed field names. */
424 /***************************************************************************/
425 throttle_spec->hash_field_names =
426 evel_throttle_hash_create(&throttle_spec->suppressed_field_names);
428 /***************************************************************************/
429 /* Create the hash table for suppressed nv pairs. */
430 /***************************************************************************/
431 nv_pairs_count = dlist_count(&throttle_spec->suppressed_nv_pairs_list);
432 if (nv_pairs_count > 0)
434 throttle_spec->hash_nv_pairs_list = calloc(1, sizeof(struct hsearch_data));
435 assert(throttle_spec->hash_nv_pairs_list != NULL);
437 /*************************************************************************/
438 /* Provide plenty of space in the table - see hcreate_r notes. */
439 /*************************************************************************/
440 if (hcreate_r(nv_pairs_count * 2, throttle_spec->hash_nv_pairs_list) == 0)
442 EVEL_ERROR("Failed to create hash table");
443 free(throttle_spec->hash_nv_pairs_list);
444 throttle_spec->hash_nv_pairs_list = NULL;
448 /***************************************************************************/
449 /* Populate the hash tables under suppressed field names. */
450 /***************************************************************************/
451 dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
452 while (dlist_item != NULL)
454 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs = dlist_item->item;
457 /*************************************************************************/
458 /* Set the key to the string, and the item to the nv_pairs. */
459 /*************************************************************************/
460 assert(nv_pairs != NULL);
461 hash_add.key = nv_pairs->nv_pair_field_name;
462 hash_add.data = nv_pairs;
463 hsearch_r(hash_add, ENTER, &add_result, throttle_spec->hash_nv_pairs_list);
465 /*************************************************************************/
466 /* Create the nv_pair_names hash since we're in here. */
467 /*************************************************************************/
468 nv_pairs->hash_nv_pair_names =
469 evel_throttle_hash_create(&nv_pairs->suppressed_nv_pair_names);
471 dlist_item = dlist_get_next(dlist_item);
477 /**************************************************************************//**
478 * Create and populate a hash table from a DLIST of keys.
480 * @param hash_keys Pointer to a DLIST of hash table keys.
481 * @return Pointer to the created hash-table, or NULL on failure.
482 *****************************************************************************/
483 struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys)
486 struct hsearch_data * hash_table;
491 /***************************************************************************/
492 /* Check preconditions. */
493 /***************************************************************************/
494 assert(hash_keys != NULL);
496 /***************************************************************************/
497 /* Count the keys and if there are any, populate the hash table with them. */
498 /***************************************************************************/
499 key_count = dlist_count(hash_keys);
502 EVEL_DEBUG("Populating table for %d keys", key_count);
504 hash_table = calloc(1, sizeof(struct hsearch_data));
505 assert(hash_table != NULL);
507 /*************************************************************************/
508 /* We need to leave plenty of space in the table - see hcreate_r notes. */
509 /*************************************************************************/
510 if (hcreate_r(key_count * 2, hash_table) != 0)
512 DLIST_ITEM * dlist_item;
513 dlist_item = dlist_get_first(hash_keys);
514 while (dlist_item != NULL)
516 assert(dlist_item->item != NULL);
518 /*********************************************************************/
519 /* Set the key and data to the item, which is a string in this case. */
520 /*********************************************************************/
522 hash_add.key = dlist_item->item;
523 hash_add.data = dlist_item->item;
524 hsearch_r(hash_add, ENTER, &add_result, hash_table);
525 dlist_item = dlist_get_next(dlist_item);
530 EVEL_ERROR("Failed to create hash table");
545 /**************************************************************************//**
546 * Free resources associated with a single ::EVEL_THROTTLE_SPEC.
548 * @param throttle_spec The ::EVEL_THROTTLE_SPEC to free.
549 *****************************************************************************/
550 void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec)
553 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
557 /***************************************************************************/
558 /* Check preconditions. */
559 /***************************************************************************/
560 assert(throttle_spec != NULL);
562 /***************************************************************************/
563 /* Free any hash tables. */
564 /***************************************************************************/
565 if (throttle_spec->hash_field_names != NULL)
567 hdestroy_r(throttle_spec->hash_field_names);
568 free(throttle_spec->hash_field_names);
570 if (throttle_spec->hash_nv_pairs_list != NULL)
572 hdestroy_r(throttle_spec->hash_nv_pairs_list);
573 free(throttle_spec->hash_nv_pairs_list);
576 /***************************************************************************/
577 /* Iterate through the linked lists, freeing memory. */
578 /***************************************************************************/
579 field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
580 while (field_name != NULL)
583 field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
586 nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
587 while (nv_pairs != NULL)
589 evel_throttle_free_nv_pair(nv_pairs);
590 nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
598 /**************************************************************************//**
599 * Free resources associated with a single ::EVEL_SUPPRESSED_NV_PAIR.
601 * @param nv_pair The ::EVEL_SUPPRESSED_NV_PAIR to free.
602 *****************************************************************************/
603 void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
605 char * suppressed_name;
609 /***************************************************************************/
610 /* Check preconditions. */
611 /***************************************************************************/
612 assert(nv_pairs != NULL);
614 /***************************************************************************/
615 /* Free any hash tables. */
616 /***************************************************************************/
617 if (nv_pairs->hash_nv_pair_names != NULL)
619 hdestroy_r(nv_pairs->hash_nv_pair_names);
620 free(nv_pairs->hash_nv_pair_names);
623 /***************************************************************************/
624 /* Iterate through the linked lists, freeing memory. */
625 /***************************************************************************/
626 suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
627 while (suppressed_name != NULL)
629 free(suppressed_name);
630 suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
632 if (nv_pairs->nv_pair_field_name != NULL)
634 free(nv_pairs->nv_pair_field_name);
641 /**************************************************************************//**
642 * Handle a JSON response from the listener, as a list of tokens from JSMN.
644 * @param chunk Memory chunk containing the JSON buffer.
645 * @param json_tokens Array of tokens to handle.
646 * @param num_tokens The number of tokens to handle.
647 * @param post The memory chunk in which to place any resulting POST.
648 * @return true if the command was handled, false otherwise.
649 *****************************************************************************/
650 bool evel_handle_command_list(const MEMORY_CHUNK * const chunk,
651 const jsmntok_t * const json_tokens,
652 const int num_tokens,
653 MEMORY_CHUNK * const post)
655 EVEL_JSON_STACK stack;
656 EVEL_JSON_STACK * json_stack = &stack;
657 EVEL_JSON_STACK_ENTRY * entry;
664 /***************************************************************************/
665 /* Check preconditions. */
666 /***************************************************************************/
667 assert(chunk != NULL);
668 assert(json_tokens != NULL);
669 assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS);
671 /***************************************************************************/
672 /* Collect one top-level item. */
673 /***************************************************************************/
674 evel_init_json_stack(json_stack, chunk);
676 /***************************************************************************/
677 /* Initialize JSON processing variables. */
678 /***************************************************************************/
679 evel_provide_throttling_state = false;
680 evel_command_type_value = NULL;
681 evel_measurement_interval_value = NULL;
682 evel_throttle_spec_domain_value = NULL;
683 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
684 evel_temp_throttle = NULL;
685 evel_json_command_state = EVEL_JCS_START;
687 /***************************************************************************/
688 /* Loop through the tokens, keeping a stack of state representing the */
689 /* nested JSON structure (see json_state). We also track our way through */
690 /* the ::EVEL_JSON_COMMAND_STATE as we go. */
691 /***************************************************************************/
692 while (json_ok && (token_index < num_tokens))
694 const jsmntok_t * const token = &json_tokens[token_index];
698 evel_debug_token(chunk, token);
701 /*************************************************************************/
702 /* We may have popped or pushed, so always re-evaluate the stack entry. */
703 /*************************************************************************/
704 entry = &json_stack->entry[json_stack->level];
709 if ((entry->json_state == EVEL_JSON_ITEM) ||
710 (entry->json_state == EVEL_JSON_VALUE))
712 json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_KEY);
716 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
717 entry->json_state, token_index, token->type);
723 if ((entry->json_state == EVEL_JSON_ITEM) ||
724 (entry->json_state == EVEL_JSON_VALUE))
726 json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_ITEM);
730 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
731 entry->json_state, token_index, token->type);
737 if (entry->json_state == EVEL_JSON_KEY)
739 evel_stack_store_key(json_stack, token);
741 else 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);
758 if (entry->json_state == EVEL_JSON_VALUE)
760 evel_stack_store_value(json_stack, token);
762 else if (entry->json_state == EVEL_JSON_ITEM)
764 evel_stack_store_item(json_stack, token);
768 EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
769 entry->json_state, token_index, token->type);
776 EVEL_ERROR("Unexpected JSON format at token %d (%d)",
777 token_index, token->type);
782 /*************************************************************************/
783 /* Pop the stack if we're counted enough nested items. */
784 /*************************************************************************/
785 evel_stack_pop(json_stack);
790 /***************************************************************************/
791 /* Cleanup the stack - we may have exited without winding it back, if the */
792 /* input was not well formed. */
793 /***************************************************************************/
794 evel_stack_cleanup(json_stack);
796 /***************************************************************************/
797 /* We may want to generate and POST a response to the command list. */
798 /***************************************************************************/
801 evel_command_list_response(post);
804 /***************************************************************************/
805 /* Make sure we're clean on exit. */
806 /***************************************************************************/
807 assert(evel_command_type_value == NULL);
808 assert(evel_measurement_interval_value == NULL);
809 assert(evel_throttle_spec_domain_value == NULL);
810 assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
811 assert(evel_temp_throttle == NULL);
818 /**************************************************************************//**
819 * Copy a copy of an element, in string form.
821 * The caller must manage memory allocated for the copied string.
823 * @param chunk Memory chunk containing the JSON buffer.
824 * @param token The token to copy from.
825 * @return the copy of the element.
826 *****************************************************************************/
827 char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
828 const jsmntok_t * const token)
835 /***************************************************************************/
836 /* Call strdup to copy the string, inserting a temporary \0 for the call. */
837 /***************************************************************************/
838 temp_char = chunk->memory[token->end];
839 chunk->memory[token->end] = '\0';
840 result = strdup(chunk->memory + token->start);
841 assert(result != NULL);
842 chunk->memory[token->end] = temp_char;
849 /**************************************************************************//**
850 * Copy a copy of an element, in string form.
852 * @param json_stack The JSON stack to initialize.
853 * @param chunk The underlying memory chunk used for parsing.
854 *****************************************************************************/
855 void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
856 const MEMORY_CHUNK * const chunk)
858 EVEL_JSON_STACK_ENTRY * entry;
862 json_stack->level = 0;
863 entry = json_stack->entry;
864 entry->json_state = EVEL_JSON_ITEM;
865 entry->json_count = 0;
866 entry->num_required = 1;
867 entry->json_key = NULL;
868 json_stack->chunk = chunk;
873 /**************************************************************************//**
874 * Push a new entry on the stack
876 * @param json_stack The stack.
877 * @param num_required The number of elements required.
878 * @param new_state The state for the new entry.
879 * @return false if we cannot push onto the stack.
880 *****************************************************************************/
881 bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
882 const int num_required,
883 const EVEL_JSON_STATE new_state)
885 EVEL_JSON_STACK_ENTRY * entry;
891 /***************************************************************************/
892 /* Check preconditions. */
893 /***************************************************************************/
894 assert(json_stack != NULL);
895 assert(json_stack->level >= 0);
896 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
897 assert((new_state == EVEL_JSON_ITEM) || (new_state == EVEL_JSON_KEY));
899 /***************************************************************************/
900 /* Check nesting depth, and stop processing if we hit the limit. */
901 /***************************************************************************/
902 if ((json_stack->level + 1) >= EVEL_JSON_STACK_DEPTH)
904 EVEL_ERROR("JSON Nesting is too deep - stop processing");
909 /***************************************************************************/
910 /* Evaluate cases where we recurse and are interested in the contents. */
911 /***************************************************************************/
912 entry = &json_stack->entry[json_stack->level];
913 key = entry->json_key;
915 /***************************************************************************/
916 /* Note that this is the key before we drop a level. */
917 /***************************************************************************/
920 EVEL_DEBUG("Push with key: %s", key);
922 switch (evel_json_command_state)
925 if (strcmp(key, "commandList") == 0)
927 evel_set_command_state(EVEL_JCS_COMMAND_LIST);
931 case EVEL_JCS_COMMAND_LIST_ENTRY:
932 if (strcmp(key, "command") == 0)
935 evel_set_command_state(EVEL_JCS_COMMAND);
939 case EVEL_JCS_COMMAND:
940 if (strcmp(key, "eventDomainThrottleSpecification") == 0)
942 evel_open_throttle_spec();
943 evel_set_command_state(EVEL_JCS_SPEC);
948 if (strcmp(key, "suppressedFieldNames") == 0)
950 evel_set_command_state(EVEL_JCS_FIELD_NAMES);
952 else if (strcmp(key, "suppressedNvPairsList") == 0)
954 evel_set_command_state(EVEL_JCS_PAIRS_LIST);
958 case EVEL_JCS_PAIRS_LIST_ENTRY:
959 if (strcmp(key, "suppressedNvPairNames") == 0)
961 evel_set_command_state(EVEL_JCS_NV_PAIR_NAMES);
965 case EVEL_JCS_FIELD_NAMES:
966 case EVEL_JCS_PAIRS_LIST:
967 case EVEL_JCS_NV_PAIR_NAMES:
969 EVEL_ERROR("Unexpected JSON key %s in state %d",
971 evel_json_command_state);
977 EVEL_DEBUG("Push with no key");
979 /*************************************************************************/
980 /* If we're pushing without a key, then we're in an array. We switch */
981 /* state based on the existing state and stack level. */
982 /*************************************************************************/
983 const int COMMAND_LIST_LEVEL = 2;
984 const int NV_PAIRS_LIST_LEVEL = 6;
986 if ((evel_json_command_state == EVEL_JCS_PAIRS_LIST) &&
987 (json_stack->level == NV_PAIRS_LIST_LEVEL))
989 /***********************************************************************/
990 /* We are entering an object within the "suppressedNvPairsList" array. */
991 /***********************************************************************/
992 evel_open_nv_pairs_list_entry();
993 evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
996 if ((evel_json_command_state == EVEL_JCS_COMMAND_LIST) &&
997 (json_stack->level == COMMAND_LIST_LEVEL))
999 /***********************************************************************/
1000 /* We are entering an object within the "commandList" array. */
1001 /***********************************************************************/
1002 evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
1006 /***************************************************************************/
1007 /* Push the stack and initialize the entry. */
1008 /***************************************************************************/
1009 json_stack->level++;
1011 EVEL_DEBUG("Stack Push -> %d", json_stack->level);
1012 entry = &json_stack->entry[json_stack->level];
1013 entry->json_count = 0;
1014 entry->num_required = num_required;
1015 entry->json_state = new_state;
1016 entry->json_key = NULL;
1026 /**************************************************************************//**
1027 * Pop any stack entries which have collected the required number of items.
1029 * @param json_stack The stack.
1030 *****************************************************************************/
1031 void evel_stack_pop(EVEL_JSON_STACK * const json_stack)
1033 EVEL_JSON_STACK_ENTRY * entry;
1038 /***************************************************************************/
1039 /* Check preconditions. */
1040 /***************************************************************************/
1041 assert(json_stack != NULL);
1042 assert(json_stack->level >= 0);
1043 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1045 entry = &json_stack->entry[json_stack->level];
1046 while ((json_stack->level > 0) && (entry->json_count == entry->num_required))
1048 key = entry->json_key;
1050 switch (evel_json_command_state)
1052 case EVEL_JCS_COMMAND_LIST:
1053 evel_set_command_state(EVEL_JCS_START);
1056 case EVEL_JCS_COMMAND_LIST_ENTRY:
1057 evel_set_command_state(EVEL_JCS_COMMAND_LIST);
1060 case EVEL_JCS_COMMAND:
1061 evel_close_command();
1062 evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
1066 evel_close_throttle_spec();
1067 evel_set_command_state(EVEL_JCS_COMMAND);
1070 case EVEL_JCS_FIELD_NAMES:
1071 evel_set_command_state(EVEL_JCS_SPEC);
1074 case EVEL_JCS_PAIRS_LIST:
1075 evel_set_command_state(EVEL_JCS_SPEC);
1078 case EVEL_JCS_PAIRS_LIST_ENTRY:
1079 evel_close_nv_pairs_list_entry();
1080 evel_set_command_state(EVEL_JCS_PAIRS_LIST);
1083 case EVEL_JCS_NV_PAIR_NAMES:
1084 evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
1091 /*************************************************************************/
1092 /* Free off any key that was duplicated and stored. */
1093 /*************************************************************************/
1097 entry->json_key = NULL;
1100 /*************************************************************************/
1101 /* We just reached the required number of key-value pairs or items, so */
1102 /* pop the stack. */
1103 /*************************************************************************/
1104 json_stack->level--;
1107 EVEL_DEBUG("Stack Pop -> %d", json_stack->level);
1109 /*************************************************************************/
1110 /* We just completed collection of an ITEM (within an ARRAY) or a VALUE */
1111 /* (within an OBJECT). Either way, we need to count it. */
1112 /*************************************************************************/
1113 entry->json_count++;
1115 /*************************************************************************/
1116 /* If we just completed a VALUE, then we expect the next element to be a */
1117 /* key, if there is a next element. */
1118 /*************************************************************************/
1119 if (entry->json_state == EVEL_JSON_VALUE)
1121 entry->json_state = EVEL_JSON_KEY;
1128 /**************************************************************************//**
1129 * Pop all stack entries, freeing any memory as we go.
1131 * @param json_stack The stack.
1132 *****************************************************************************/
1133 void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack)
1135 EVEL_JSON_STACK_ENTRY * entry;
1139 /***************************************************************************/
1140 /* Check preconditions. */
1141 /***************************************************************************/
1142 assert(json_stack != NULL);
1143 assert(json_stack->level >= 0);
1144 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1146 entry = &json_stack->entry[json_stack->level];
1147 while ((json_stack->level > 0))
1149 /*************************************************************************/
1150 /* Free off any key that was duplicated and stored. */
1151 /*************************************************************************/
1152 if (entry->json_key != NULL)
1154 free(entry->json_key);
1155 entry->json_key = NULL;
1158 /*************************************************************************/
1159 /* We just reached the required number of key-value pairs or items, so */
1160 /* pop the stack. */
1161 /*************************************************************************/
1162 json_stack->level--;
1166 /***************************************************************************/
1167 /* If we hit EVEL_JSON_STACK_DEPTH, we exit the loop and can leave these */
1168 /* values hanging - so clean them up. */
1169 /***************************************************************************/
1170 if (evel_command_type_value != NULL)
1172 free(evel_command_type_value);
1173 evel_command_type_value = NULL;
1175 if (evel_measurement_interval_value != NULL)
1177 free(evel_measurement_interval_value);
1178 evel_measurement_interval_value = NULL;
1180 if (evel_throttle_spec_domain_value != NULL)
1182 free(evel_throttle_spec_domain_value);
1183 evel_throttle_spec_domain_value = NULL;
1185 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1186 if (evel_temp_throttle != NULL)
1188 evel_throttle_free(evel_temp_throttle);
1189 evel_temp_throttle = NULL;
1195 /**************************************************************************//**
1196 * Store a key in the JSON stack.
1198 * We always store the most recent key at each level in the stack.
1200 * @param json_stack The stack.
1201 * @param token The token holding the key.
1202 *****************************************************************************/
1203 void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
1204 const jsmntok_t * const token)
1206 EVEL_JSON_STACK_ENTRY * entry;
1210 /***************************************************************************/
1211 /* Check preconditions. */
1212 /***************************************************************************/
1213 assert(json_stack != NULL);
1214 assert(json_stack->level >= 0);
1215 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1217 /***************************************************************************/
1218 /* Free any previously stored key, replacing it with the new one. */
1219 /***************************************************************************/
1220 entry = &json_stack->entry[json_stack->level];
1221 if (entry->json_key != NULL)
1223 free(entry->json_key);
1225 entry->json_key = evel_stack_strdup(json_stack->chunk, token);
1227 /***************************************************************************/
1228 /* Switch state to collecting the corresponding value. */
1229 /***************************************************************************/
1230 entry->json_state = EVEL_JSON_VALUE;
1232 EVEL_DEBUG("Stored key: %s", entry->json_key);
1236 /**************************************************************************//**
1237 * Store a value in the JSON stack.
1239 * @param json_stack The stack.
1240 * @param token The token holding the value.
1241 *****************************************************************************/
1242 void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
1243 const jsmntok_t * const token)
1245 EVEL_JSON_STACK_ENTRY * entry;
1251 /***************************************************************************/
1252 /* Check preconditions. */
1253 /***************************************************************************/
1254 assert(json_stack != NULL);
1255 assert(json_stack->level >= 0);
1256 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1258 /***************************************************************************/
1259 /* Based on the (key, state), work out whether we're expecting a value, */
1260 /* then store or ignore it as required. */
1261 /***************************************************************************/
1262 entry = &json_stack->entry[json_stack->level];
1263 value = evel_stack_strdup(json_stack->chunk, token);
1265 EVEL_DEBUG("Store value: %s", value);
1267 switch (evel_json_command_state)
1269 case EVEL_JCS_COMMAND:
1270 if (strcmp(entry->json_key, "commandType") == 0)
1272 evel_command_type_value = value;
1275 else if (strcmp(entry->json_key, "measurementInterval") == 0)
1277 evel_measurement_interval_value = value;
1283 if (strcmp(entry->json_key, "eventDomain") == 0)
1285 evel_throttle_spec_domain_value = value;
1290 case EVEL_JCS_PAIRS_LIST_ENTRY:
1291 if (strcmp(entry->json_key, "nvPairFieldName") == 0)
1293 evel_store_nv_pair_field_name(value);
1299 EVEL_DEBUG("Ignoring value in state: %s",
1300 evel_jcs_strings[evel_json_command_state]);
1306 EVEL_DEBUG("Ignored value: %s", value);
1310 /***************************************************************************/
1311 /* Switch state to another key. */
1312 /***************************************************************************/
1313 entry->json_state = EVEL_JSON_KEY;
1315 /***************************************************************************/
1316 /* Count the key-value pair. */
1317 /***************************************************************************/
1318 entry->json_count++;
1323 /**************************************************************************//**
1324 * Store an item in the JSON stack - a string or primitive in an array.
1326 * @param json_stack The stack.
1327 * @param token The token holding the item.
1328 *****************************************************************************/
1329 void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
1330 const jsmntok_t * const token)
1332 EVEL_JSON_STACK_ENTRY * entry;
1338 /***************************************************************************/
1339 /* Check preconditions. */
1340 /***************************************************************************/
1341 assert(json_stack != NULL);
1342 assert(json_stack->level >= 0);
1343 assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1345 /***************************************************************************/
1346 /* Based on the state, work out whether we're expecting an item, then */
1347 /* store or ignore it as required. */
1348 /***************************************************************************/
1349 entry = &json_stack->entry[json_stack->level];
1350 item = evel_stack_strdup(json_stack->chunk, token);
1352 EVEL_DEBUG("Store item: %s", item);
1354 switch (evel_json_command_state)
1356 case EVEL_JCS_NV_PAIR_NAMES:
1357 evel_store_nv_pair_name(item);
1361 case EVEL_JCS_FIELD_NAMES:
1362 evel_store_suppressed_field_name(item);
1367 EVEL_DEBUG("Ignoring item in state: %s",
1368 evel_jcs_strings[evel_json_command_state]);
1374 EVEL_DEBUG("Ignored item: %s", item);
1378 /***************************************************************************/
1379 /* We need another item. This is purely defensive. */
1380 /***************************************************************************/
1381 entry->json_state = EVEL_JSON_ITEM;
1383 /***************************************************************************/
1384 /* Count the item. */
1385 /***************************************************************************/
1386 entry->json_count++;
1389 /**************************************************************************//**
1390 * Set the JSON command state to a new value.
1392 * @param new_state The new state to set.
1393 *****************************************************************************/
1394 void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state)
1398 /***************************************************************************/
1399 /* Check preconditions. */
1400 /***************************************************************************/
1401 assert(evel_json_command_state < EVEL_JCS_MAX);
1402 assert(new_state < EVEL_JCS_MAX);
1404 /***************************************************************************/
1405 /* Provide common debug, and set the new state. */
1406 /***************************************************************************/
1407 EVEL_DEBUG("Command State: %s -> %s",
1408 evel_jcs_strings[evel_json_command_state],
1409 evel_jcs_strings[new_state]);
1410 evel_json_command_state = new_state;
1415 /**************************************************************************//**
1416 * Produce debug output from a JSON token.
1418 * @param chunk Memory chunk containing the JSON buffer.
1419 * @param token Token to dump.
1420 *****************************************************************************/
1421 void evel_debug_token(const MEMORY_CHUNK * const chunk,
1422 const jsmntok_t * const token)
1428 /***************************************************************************/
1429 /* Check preconditions. */
1430 /***************************************************************************/
1431 assert(token->type > 0);
1432 assert(token->type < JSON_TOKEN_TYPES);
1434 /***************************************************************************/
1435 /* Log the token, leaving it in the state in which it started. */
1436 /***************************************************************************/
1437 temp_char = chunk->memory[token->end];
1438 chunk->memory[token->end] = '\0';
1439 EVEL_DEBUG("JSON token type: %s", evel_json_token_strings[token->type]);
1440 EVEL_DEBUG("JSON token: %s", chunk->memory + token->start);
1441 chunk->memory[token->end] = temp_char;
1446 /**************************************************************************//**
1447 * Post a response to the commandList.
1449 * @param post Memory chunk in which to post a response.
1450 *****************************************************************************/
1451 void evel_command_list_response(MEMORY_CHUNK * const post)
1457 /***************************************************************************/
1458 /* Check preconditions. */
1459 /***************************************************************************/
1460 assert(post != NULL);
1461 assert(post->memory == NULL);
1463 if (evel_provide_throttling_state)
1465 EVEL_DEBUG("Provide throttling state");
1467 /*************************************************************************/
1468 /* Encode the response, making it printf-able for debug. */
1469 /*************************************************************************/
1470 json_post = malloc(EVEL_MAX_JSON_BODY);
1471 assert(json_post != NULL);
1472 post->size = evel_json_encode_throttle(json_post, EVEL_MAX_JSON_BODY - 1);
1473 post->memory = json_post;
1474 post->memory[post->size] = '\0';
1475 evel_provide_throttling_state = false;
1481 /**************************************************************************//**
1482 * Encode the full throttling specification according to AT&T's schema.
1484 * @param json Pointer to where to store the JSON encoded data.
1485 * @param max_size Size of storage available in json_body.
1486 * @returns Number of bytes actually written.
1487 *****************************************************************************/
1488 int evel_json_encode_throttle(char * const json, const int max_size)
1497 /***************************************************************************/
1498 /* Check preconditions. */
1499 /***************************************************************************/
1500 assert(json != NULL);
1501 assert(max_size > 0);
1503 /***************************************************************************/
1504 /* Work out if we're throttled. */
1505 /***************************************************************************/
1507 for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1509 if (evel_throttle_spec[domain] != NULL)
1515 /***************************************************************************/
1516 /* Encode the response. */
1517 /***************************************************************************/
1519 offset += snprintf(json + offset, max_size - offset,
1520 "{\"eventThrottlingState\": {");
1521 offset += snprintf(json + offset, max_size - offset,
1522 "\"eventThrottlingMode\": \"%s\"",
1523 throttled ? "throttled" : "normal");
1526 offset += snprintf(json + offset, max_size - offset,
1527 ", \"eventDomainThrottleSpecificationList\": [");
1529 domain_added = false;
1530 for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1532 if (evel_throttle_spec[domain] != NULL)
1536 offset += snprintf(json + offset, max_size - offset, ", ");
1539 offset += evel_json_encode_throttle_spec(json + offset,
1542 domain_added = true;
1546 offset += snprintf(json + offset, max_size - offset, "]");
1549 offset += snprintf(json + offset, max_size - offset, "}}");
1556 /**************************************************************************//**
1557 * Encode a throttling specification for a domain.
1559 * @param json Pointer to where to store the JSON encoded data.
1560 * @param max_size Size of storage available in json_body.
1561 * @returns Number of bytes actually written.
1562 *****************************************************************************/
1563 int evel_json_encode_throttle_spec(char * const json,
1565 const EVEL_EVENT_DOMAINS domain)
1568 EVEL_THROTTLE_SPEC * throttle_spec;
1569 DLIST_ITEM * dlist_item;
1572 /***************************************************************************/
1573 /* Check preconditions. */
1574 /***************************************************************************/
1575 assert(domain >= EVEL_DOMAIN_FAULT);
1576 assert(domain < EVEL_MAX_DOMAINS);
1577 assert(evel_throttle_spec[domain] != NULL);
1579 throttle_spec = evel_throttle_spec[domain];
1581 /***************************************************************************/
1582 /* Encode the domain. */
1583 /***************************************************************************/
1585 offset += snprintf(json + offset, max_size - offset,
1587 offset += snprintf(json + offset, max_size - offset,
1588 "\"eventDomain\": \"%s\"",
1589 evel_domain_strings[domain]);
1591 /***************************************************************************/
1592 /* Encode "suppressedFieldNames". */
1593 /***************************************************************************/
1594 dlist_item = dlist_get_first(&throttle_spec->suppressed_field_names);
1595 if (dlist_item != NULL)
1597 offset += snprintf(json + offset, max_size - offset,
1598 ", \"suppressedFieldNames\": [");
1599 while (dlist_item != NULL)
1601 char * suppressed_field = dlist_item->item;
1602 assert(suppressed_field != NULL);
1604 offset += snprintf(json + offset, max_size - offset,
1605 "\"%s\"", suppressed_field);
1606 dlist_item = dlist_get_next(dlist_item);
1607 if (dlist_item != NULL)
1609 offset += snprintf(json + offset, max_size - offset, ", ");
1613 offset += snprintf(json + offset, max_size - offset, "]");
1616 /***************************************************************************/
1617 /* Encode "suppressedNvPairsList". */
1618 /***************************************************************************/
1619 dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
1620 if (dlist_item != NULL)
1622 offset += snprintf(json + offset, max_size - offset,
1623 ", \"suppressedNvPairsList\": [");
1624 while (dlist_item != NULL)
1626 offset += evel_json_encode_nv_pairs(json + offset,
1629 dlist_item = dlist_get_next(dlist_item);
1630 if (dlist_item != NULL)
1632 offset += snprintf(json + offset, max_size - offset, ", ");
1636 offset += snprintf(json + offset, max_size - offset, "]");
1639 offset += snprintf(json + offset, max_size - offset, "}");
1646 /**************************************************************************//**
1647 * Encode a single "suppressedNvPairsListEntry".
1649 * @param json Pointer to where to store the JSON encoded data.
1650 * @param max_size Size of storage available in json_body.
1651 * @returns Number of bytes actually written.
1652 *****************************************************************************/
1653 int evel_json_encode_nv_pairs(char * const json,
1655 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
1657 DLIST_ITEM * dlist_item;
1661 /***************************************************************************/
1662 /* Check preconditions. */
1663 /***************************************************************************/
1664 assert(nv_pairs != NULL);
1665 assert(nv_pairs->nv_pair_field_name != NULL);
1666 assert(!dlist_is_empty(&nv_pairs->suppressed_nv_pair_names));
1668 /***************************************************************************/
1670 /***************************************************************************/
1672 offset += snprintf(json + offset, max_size - offset, "{");
1673 offset += snprintf(json + offset, max_size - offset,
1674 "\"nvPairFieldName\": \"%s\"",
1675 nv_pairs->nv_pair_field_name);
1676 dlist_item = dlist_get_first(&nv_pairs->suppressed_nv_pair_names);
1677 offset += snprintf(json + offset, max_size - offset,
1678 ", \"suppressedNvPairNames\": [");
1679 while (dlist_item != NULL)
1681 name = dlist_item->item;
1682 assert(name != NULL);
1683 offset += snprintf(json + offset, max_size - offset, "\"%s\"", name);
1684 dlist_item = dlist_get_next(dlist_item);
1685 if (dlist_item != NULL)
1687 offset += snprintf(json + offset, max_size - offset, ", ");
1690 offset += snprintf(json + offset, max_size - offset, "]");
1691 offset += snprintf(json + offset, max_size - offset, "}");
1698 /**************************************************************************//**
1699 * Method called when we open a "command" object.
1700 *****************************************************************************/
1701 void evel_open_command()
1705 /***************************************************************************/
1706 /* Make some assertions. */
1707 /***************************************************************************/
1708 assert(evel_command_type_value == NULL);
1709 assert(evel_measurement_interval_value == NULL);
1714 /**************************************************************************//**
1715 * Method called when we close a "command" object.
1716 *****************************************************************************/
1717 void evel_close_command()
1721 /***************************************************************************/
1722 /* If a commandType was provided, fan out and handle it now what we have */
1723 /* fathered all related information. */
1725 /* Note that we handle throttling specification and measurement interval */
1726 /* updates immediately on closing the command (not the list). We could */
1727 /* reject *all* commands in a list if any of them are invalid, but we are */
1728 /* take a best-effort strategy here - any valid-looking command gets */
1729 /* implemented regardless of what follows. */
1730 /***************************************************************************/
1731 if (evel_command_type_value != NULL)
1733 EVEL_DEBUG("Closing command %s", evel_command_type_value);
1735 if (strcmp(evel_command_type_value, "provideThrottlingState") == 0)
1737 evel_provide_throttling_state = true;
1739 else if (strcmp(evel_command_type_value, "throttlingSpecification") == 0)
1741 evel_set_throttling_spec();
1743 else if (strcmp(evel_command_type_value, "measurementIntervalChange") == 0)
1745 evel_set_measurement_interval();
1749 EVEL_ERROR("Ignoring unknown commandType: %s\n",
1750 evel_command_type_value);
1753 /*************************************************************************/
1754 /* Free the captured "commandType" value. */
1755 /*************************************************************************/
1756 free(evel_command_type_value);
1757 evel_command_type_value = NULL;
1760 /***************************************************************************/
1761 /* There could be an unused working throttle spec at this point - if the */
1762 /* "throttlingSpecification" commandType was not provided, or an invalid */
1763 /* domain was provided, or was not provided at all. */
1764 /***************************************************************************/
1765 if (evel_temp_throttle != NULL)
1767 evel_throttle_free(evel_temp_throttle);
1768 evel_temp_throttle = NULL;
1771 /***************************************************************************/
1772 /* Similarly, the domain could be set. */
1773 /***************************************************************************/
1774 evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1776 /***************************************************************************/
1777 /* There could be an unused measurement interval value at this point - if */
1778 /* the "measurementIntervalChange" command was not provided. */
1779 /***************************************************************************/
1780 if (evel_measurement_interval_value != NULL)
1782 free(evel_measurement_interval_value);
1783 evel_measurement_interval_value = NULL;
1789 /**************************************************************************//**
1790 * Set the provided throttling specification, when the command closes.
1791 *****************************************************************************/
1792 void evel_set_throttling_spec()
1796 if ((evel_throttle_spec_domain >= 0) &&
1797 (evel_throttle_spec_domain < EVEL_MAX_DOMAINS))
1799 EVEL_DEBUG("Updating throttle spec for domain: %s",
1800 evel_domain_strings[evel_throttle_spec_domain]);
1802 /*************************************************************************/
1803 /* Free off the previous throttle specification for the domain, if there */
1805 /*************************************************************************/
1806 if (evel_throttle_spec[evel_throttle_spec_domain] != NULL)
1808 evel_throttle_free(evel_throttle_spec[evel_throttle_spec_domain]);
1811 /*************************************************************************/
1812 /* Finalize the working throttling spec, if there is one. */
1813 /*************************************************************************/
1814 if (evel_temp_throttle != NULL)
1816 evel_throttle_finalize(evel_temp_throttle);
1819 /*************************************************************************/
1820 /* Replace the throttle specification for the domain with the working */
1821 /* throttle specification. This could be NULL, if an empty throttle */
1822 /* specification has been received for a domain. */
1823 /*************************************************************************/
1824 evel_throttle_spec[evel_throttle_spec_domain] = evel_temp_throttle;
1825 evel_temp_throttle = NULL;
1831 /**************************************************************************//**
1832 * Set the provided measurement interval, when the command closes.
1833 *****************************************************************************/
1834 void evel_set_measurement_interval()
1838 if (evel_measurement_interval_value != NULL)
1840 const long int value = strtol(evel_measurement_interval_value, NULL, 10);
1842 if ((value >= 0) && (value <= INT_MAX))
1844 /***********************************************************************/
1845 /* Lock, update, unlock. */
1846 /***********************************************************************/
1847 EVEL_DEBUG("Updating measurement interval to %d\n", value);
1849 pthread_mutex_lock(&evel_measurement_interval_mutex);
1850 evel_measurement_interval = value;
1851 pthread_mutex_unlock(&evel_measurement_interval_mutex);
1855 EVEL_ERROR("Ignoring invalid measurement interval: %s",
1856 evel_measurement_interval_value);
1863 /**************************************************************************//**
1864 * Method called when we open an "eventDomainThrottleSpecification" object.
1865 *****************************************************************************/
1866 void evel_open_throttle_spec()
1870 /***************************************************************************/
1871 /* Check preconditions. */
1872 /***************************************************************************/
1873 assert(evel_throttle_spec_domain_value == NULL);
1874 assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
1875 assert(evel_temp_throttle == NULL);
1877 /***************************************************************************/
1878 /* Allocate and initialize an ::EVEL_THROTTLE_SPEC in which to hold */
1879 /* captured JSON elements. */
1880 /***************************************************************************/
1881 evel_temp_throttle = malloc(sizeof(EVEL_THROTTLE_SPEC));
1882 assert(evel_temp_throttle != NULL);
1883 dlist_initialize(&evel_temp_throttle->suppressed_field_names);
1884 dlist_initialize(&evel_temp_throttle->suppressed_nv_pairs_list);
1885 evel_temp_throttle->hash_field_names = NULL;
1886 evel_temp_throttle->hash_nv_pairs_list = NULL;
1891 /**************************************************************************//**
1892 * Method called when we close an "eventDomainThrottleSpecification" object.
1893 *****************************************************************************/
1894 void evel_close_throttle_spec()
1898 /***************************************************************************/
1899 /* Decode, free and blank a captured event domain value. */
1900 /***************************************************************************/
1901 if (evel_throttle_spec_domain_value != NULL)
1903 evel_throttle_spec_domain =
1904 evel_decode_domain(evel_throttle_spec_domain_value);
1905 free(evel_throttle_spec_domain_value);
1906 evel_throttle_spec_domain_value = NULL;
1909 /***************************************************************************/
1910 /* Free off an empty working throttle spec, to stop it being used. This */
1911 /* state should be represented by a NULL pointer for the domain. */
1912 /***************************************************************************/
1913 if (evel_temp_throttle != NULL)
1915 if (dlist_is_empty(&evel_temp_throttle->suppressed_field_names) &&
1916 dlist_is_empty(&evel_temp_throttle->suppressed_nv_pairs_list))
1918 free(evel_temp_throttle);
1919 evel_temp_throttle = NULL;
1926 /**************************************************************************//**
1927 * Convert a value for an "eventDomain" into an ::EVEL_EVENT_DOMAINS.
1929 * @param domain_value The domain string value to decode.
1930 * @returns The matching ::EVEL_EVENT_DOMAINS, or ::EVEL_MAX_DOMAINS on error.
1931 *****************************************************************************/
1932 EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value)
1934 EVEL_EVENT_DOMAINS result;
1939 /***************************************************************************/
1940 /* Check preconditions. */
1941 /***************************************************************************/
1942 assert(domain_value != NULL);
1944 result = EVEL_MAX_DOMAINS;
1945 for (ii = EVEL_DOMAIN_FAULT; ii < EVEL_MAX_DOMAINS; ii++)
1947 assert(evel_domain_strings[ii] != NULL);
1948 if (strcmp(evel_domain_strings[ii], domain_value) == 0)
1959 /**************************************************************************//**
1960 * Method called when we open a "suppressedNvPairsListEntry" object.
1961 *****************************************************************************/
1962 void evel_open_nv_pairs_list_entry()
1964 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1968 /***************************************************************************/
1969 /* Check preconditions. */
1970 /***************************************************************************/
1971 assert(evel_temp_throttle != NULL);
1973 /***************************************************************************/
1974 /* Allocate and initialize an ::EVEL_SUPPRESSED_NV_PAIRS, and add it to */
1976 /***************************************************************************/
1977 nv_pairs = malloc(sizeof(EVEL_SUPPRESSED_NV_PAIRS));
1978 assert(nv_pairs != NULL);
1979 nv_pairs->nv_pair_field_name = NULL;
1980 dlist_initialize(&nv_pairs->suppressed_nv_pair_names);
1981 nv_pairs->hash_nv_pair_names = NULL;
1982 dlist_push_last(&evel_temp_throttle->suppressed_nv_pairs_list, nv_pairs);
1987 /**************************************************************************//**
1988 * Method called when we close a "suppressedNvPairsListEntry" object.
1989 *****************************************************************************/
1990 void evel_close_nv_pairs_list_entry()
1992 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1993 EVEL_SUPPRESSED_NV_PAIRS * popped;
1997 /***************************************************************************/
1998 /* Get the latest nv pairs. This also performs the required checks. */
1999 /***************************************************************************/
2000 nv_pairs = evel_get_last_nv_pairs();
2002 /***************************************************************************/
2003 /* For a "suppressedNvPairsListEntry" to have any meaning, we need both */
2004 /* "nvPairFieldName" and "suppressedNvPairNames". If we don't, then pop */
2005 /* and free whatever we just collected. */
2006 /***************************************************************************/
2007 if ((nv_pairs->nv_pair_field_name == NULL) ||
2008 dlist_is_empty(&nv_pairs->suppressed_nv_pair_names))
2010 popped = dlist_pop_last(&evel_temp_throttle->suppressed_nv_pairs_list);
2011 assert(popped == nv_pairs);
2012 evel_throttle_free_nv_pair(popped);
2018 /**************************************************************************//**
2019 * Store an "nvPairFieldName" value in the working throttle spec.
2021 * @param value The value to store.
2022 *****************************************************************************/
2023 void evel_store_nv_pair_field_name(char * const value)
2025 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2029 /***************************************************************************/
2030 /* Get the latest nv pairs. This also performs the required checks. */
2031 /***************************************************************************/
2032 nv_pairs = evel_get_last_nv_pairs();
2034 /***************************************************************************/
2035 /* Store the value. */
2036 /***************************************************************************/
2037 nv_pairs->nv_pair_field_name = value;
2042 /**************************************************************************//**
2043 * Store a "suppressedNvPairNames" item in the working throttle spec.
2045 * @param item The item to store.
2046 *****************************************************************************/
2047 void evel_store_nv_pair_name(char * const item)
2049 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2053 /***************************************************************************/
2054 /* Get the latest nv pairs. This also performs the required checks. */
2055 /***************************************************************************/
2056 nv_pairs = evel_get_last_nv_pairs();
2058 /***************************************************************************/
2059 /* Store the item. */
2060 /***************************************************************************/
2061 dlist_push_last(&nv_pairs->suppressed_nv_pair_names, item);
2066 /**************************************************************************//**
2067 * Store a "suppressedFieldNames" item in the working throttle spec.
2069 * @param item The item to store.
2070 *****************************************************************************/
2071 void evel_store_suppressed_field_name(char * const item)
2075 /***************************************************************************/
2076 /* Check preconditions. */
2077 /***************************************************************************/
2078 assert(evel_temp_throttle != NULL);
2080 /***************************************************************************/
2081 /* Store the item. */
2082 /***************************************************************************/
2083 dlist_push_last(&evel_temp_throttle->suppressed_field_names, item);
2088 /**************************************************************************//**
2089 * Get the last added suppressed nv pairs list entry in the working spec.
2091 * @returns The last entry.
2092 *****************************************************************************/
2093 EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs()
2095 DLIST_ITEM * dlist_item;
2096 EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2100 /***************************************************************************/
2101 /* Check preconditions. */
2102 /***************************************************************************/
2103 assert(evel_temp_throttle != NULL);
2105 /***************************************************************************/
2106 /* Get the pair that was added when we opened the list entry. */
2107 /***************************************************************************/
2108 dlist_item = dlist_get_last(&evel_temp_throttle->suppressed_nv_pairs_list);
2109 assert(dlist_item != NULL);
2110 nv_pairs = dlist_item->item;
2111 assert(nv_pairs != NULL);