AT&T ECOMP Vendor Event Listener library  0.1
evel_throttle.c
Go to the documentation of this file.
1 /**************************************************************************/
40 #define _GNU_SOURCE
41 #include <string.h>
42 #include <assert.h>
43 #include <stdlib.h>
44 #include <limits.h>
45 #include <pthread.h>
46 #include <search.h>
47 
48 #include "evel_throttle.h"
49 
50 /*****************************************************************************/
51 /* The Event Throttling State for all domains, indexed by */
52 /* ::EVEL_EVENT_DOMAINS, corresponding to JSON eventDomain. */
53 /* */
54 /* A given domain is in a throttled state if ::evel_throttle_spec is */
55 /* non-NULL. */
56 /*****************************************************************************/
58 
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;
64 
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;
70 
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;
76 
77 /*****************************************************************************/
78 /* Holder for the "commandType" value during JSON processing. */
79 /*****************************************************************************/
80 static char * evel_command_type_value;
81 
82 /*****************************************************************************/
83 /* Holder for the "measurementInterval" value during JSON processing. */
84 /*****************************************************************************/
85 static char * evel_measurement_interval_value;
86 
87 /*****************************************************************************/
88 /* Holder for the "eventDomain" value during JSON processing. */
89 /*****************************************************************************/
90 static char * evel_throttle_spec_domain_value;
91 
92 /*****************************************************************************/
93 /* Decoded version of ::evel_throttle_spec_domain_value. */
94 /*****************************************************************************/
95 static EVEL_EVENT_DOMAINS evel_throttle_spec_domain;
96 
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;
102 
103 /*****************************************************************************/
104 /* State tracking our progress through the command list */
105 /*****************************************************************************/
107 
108 /*****************************************************************************/
109 /* Debug strings for ::EVEL_JSON_COMMAND_STATE. */
110 /*****************************************************************************/
111 static const char * const evel_jcs_strings[EVEL_JCS_MAX] = {
112  "EVEL_JCS_START",
113  "EVEL_JCS_COMMAND_LIST",
114  "EVEL_JCS_COMMAND_LIST_ENTRY",
115  "EVEL_JCS_COMMAND",
116  "EVEL_JCS_SPEC",
117  "EVEL_JCS_FIELD_NAMES",
118  "EVEL_JCS_PAIRS_LIST",
119  "EVEL_JCS_PAIRS_LIST_ENTRY",
120  "EVEL_JCS_NV_PAIR_NAMES"
121 };
122 
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] = {
128  "JSMN_UNDEFINED",
129  "JSMN_OBJECT",
130  "JSMN_ARRAY",
131  "JSMN_STRING",
132  "JSMN_PRIMITIVE"
133 };
134 
135 /*****************************************************************************/
136 /* Debug strings for JSON domains. */
137 /*****************************************************************************/
138 static const char * evel_domain_strings[EVEL_MAX_DOMAINS] = {
139  "internal",
140  "heartbeat",
141  "fault",
142  "measurementsForVfScaling",
143  "mobileFlow",
144  "report",
145  "serviceEvents",
146  "signaling",
147  "stateChange",
148  "syslog",
149  "other"
150 };
151 
152 /*****************************************************************************/
153 /* Local prototypes. */
154 /*****************************************************************************/
155 static void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec);
156 static struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys);
157 static void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec);
158 static void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
159 static void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
160  const MEMORY_CHUNK * const chunk);
161 static bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
162  const int num_required,
163  const EVEL_JSON_STATE new_state);
164 static void evel_stack_pop(EVEL_JSON_STACK * const json_stack);
165 static void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack);
166 static char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
167  const jsmntok_t * const token);
168 static void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
169  const jsmntok_t * const token);
170 static void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
171  const jsmntok_t * const token);
172 static void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
173  const jsmntok_t * const token);
174 static void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state);
175 static void evel_debug_token(const MEMORY_CHUNK * const chunk,
176  const jsmntok_t * const token);
177 static void evel_command_list_response(MEMORY_CHUNK * const post);
178 static int evel_json_encode_throttle(char * const json, const int max_size);
179 static int evel_json_encode_throttle_spec(char * const json,
180  const int max_size,
181  const EVEL_EVENT_DOMAINS domain);
182 static int evel_json_encode_nv_pairs(char * const json,
183  const int max_size,
184  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
185 static void evel_close_command();
186 static void evel_open_command();
187 static void evel_set_throttling_spec();
188 static void evel_set_measurement_interval();
189 static void evel_open_throttle_spec();
190 static void evel_close_throttle_spec();
191 static EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value);
192 static void evel_open_nv_pairs_list_entry();
193 static void evel_close_nv_pairs_list_entry();
194 static void evel_store_nv_pair_field_name(char * const value);
195 static void evel_store_nv_pair_name(char * const item);
196 static void evel_store_suppressed_field_name(char * const item);
197 static EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs();
198 
199 /**************************************************************************/
207 {
208  int result;
209 
210  EVEL_ENTER();
211 
212  /***************************************************************************/
213  /* Lock, read, unlock. */
214  /***************************************************************************/
215  pthread_mutex_lock(&evel_measurement_interval_mutex);
216  result = evel_measurement_interval;
217  pthread_mutex_unlock(&evel_measurement_interval_mutex);
218 
219  EVEL_EXIT();
220 
221  return result;
222 }
223 
224 /**************************************************************************/
230 {
231  EVEL_THROTTLE_SPEC * result;
232 
233  EVEL_ENTER();
234 
235  /***************************************************************************/
236  /* Check preconditions. */
237  /***************************************************************************/
238  assert(domain < EVEL_MAX_DOMAINS);
239 
240  result = evel_throttle_spec[domain];
241 
242  EVEL_EXIT();
243 
244  return result;
245 }
246 
247 /**************************************************************************/
255  const char * const field_name)
256 {
257  bool suppress = false;
258 
259  EVEL_ENTER();
260 
261  /***************************************************************************/
262  /* Check preconditions. */
263  /***************************************************************************/
264  assert(field_name != NULL);
265 
266  /***************************************************************************/
267  /* If the throttle spec and hash table exist, query the field_names table. */
268  /***************************************************************************/
269  if ((throttle_spec != NULL) && (throttle_spec->hash_field_names != NULL))
270  {
271  ENTRY hash_query;
272  ENTRY * hash_result;
273  hash_query.key = (char * const) field_name;
274  suppress = (hsearch_r(hash_query,
275  FIND,
276  &hash_result,
277  throttle_spec->hash_field_names) != 0);
278  }
279 
280  EVEL_EXIT();
281 
282  return suppress;
283 }
284 
285 /**************************************************************************/
294  const char * const field_name,
295  const char * const name)
296 {
297  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
298  bool hit = false;
299  bool suppress = false;
300 
301  EVEL_ENTER();
302 
303  /***************************************************************************/
304  /* Check preconditions. */
305  /***************************************************************************/
306  assert(field_name != NULL);
307  assert(name != NULL);
308 
309  /***************************************************************************/
310  /* If the throttle spec and hash table exist, query the nv_pairs table. */
311  /***************************************************************************/
312  if ((throttle_spec != NULL) && (throttle_spec->hash_nv_pairs_list != NULL))
313  {
314  ENTRY hash_query;
315  ENTRY * hash_result;
316  hash_query.key = (char * const) field_name;
317  hit = (hsearch_r(hash_query,
318  FIND,
319  &hash_result,
320  throttle_spec->hash_nv_pairs_list) != 0);
321  if (hit)
322  {
323  nv_pairs = hash_result->data;
324  }
325  }
326 
327  /***************************************************************************/
328  /* If we got a hit, and the nv_pairs and hash table exist, query the */
329  /* nv_pairs table. */
330  /***************************************************************************/
331  if (hit && (nv_pairs != NULL) && (nv_pairs->hash_nv_pair_names != NULL))
332  {
333  ENTRY hash_query;
334  ENTRY * hash_result;
335  hash_query.key = (char * const) name;
336  suppress = (hsearch_r(hash_query,
337  FIND,
338  &hash_result,
339  nv_pairs->hash_nv_pair_names) != 0);
340  }
341 
342  EVEL_EXIT();
343 
344  return suppress;
345 }
346 
347 /**************************************************************************/
353 {
354  int pthread_rc;
355  int ii;
356 
357  EVEL_ENTER();
358 
359  for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
360  {
361  evel_throttle_spec[ii] = NULL;
362  }
363 
364  pthread_rc = pthread_mutex_init(&evel_measurement_interval_mutex, NULL);
365  assert(pthread_rc == 0);
366 
367  evel_measurement_interval = EVEL_MEASUREMENT_INTERVAL_UKNOWN;
368 
369  EVEL_EXIT();
370 }
371 
372 /**************************************************************************/
378 {
379  int pthread_rc;
380  int ii;
381 
382  EVEL_ENTER();
383 
384  for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
385  {
386  if (evel_throttle_spec[ii] != NULL)
387  {
388  evel_throttle_free(evel_throttle_spec[ii]);
389  evel_throttle_spec[ii] = NULL;
390  }
391  }
392 
393  pthread_rc = pthread_mutex_destroy(&evel_measurement_interval_mutex);
394  assert(pthread_rc == 0);
395 
396  EVEL_EXIT();
397 }
398 
399 /**************************************************************************/
407 void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec)
408 {
409  int nv_pairs_count;
411  ENTRY * add_result;
412 
413  EVEL_ENTER();
414 
415  /***************************************************************************/
416  /* Check preconditions. */
417  /***************************************************************************/
418  assert(throttle_spec != NULL);
419 
420  /***************************************************************************/
421  /* Populate the hash table for suppressed field names. */
422  /***************************************************************************/
423  throttle_spec->hash_field_names =
424  evel_throttle_hash_create(&throttle_spec->suppressed_field_names);
425 
426  /***************************************************************************/
427  /* Create the hash table for suppressed nv pairs. */
428  /***************************************************************************/
429  nv_pairs_count = dlist_count(&throttle_spec->suppressed_nv_pairs_list);
430  if (nv_pairs_count > 0)
431  {
432  throttle_spec->hash_nv_pairs_list = calloc(1, sizeof(struct hsearch_data));
433  assert(throttle_spec->hash_nv_pairs_list != NULL);
434 
435  /*************************************************************************/
436  /* Provide plenty of space in the table - see hcreate_r notes. */
437  /*************************************************************************/
438  if (hcreate_r(nv_pairs_count * 2, throttle_spec->hash_nv_pairs_list) == 0)
439  {
440  EVEL_ERROR("Failed to create hash table");
441  free(throttle_spec->hash_nv_pairs_list);
442  throttle_spec->hash_nv_pairs_list = NULL;
443  }
444  }
445 
446  /***************************************************************************/
447  /* Populate the hash tables under suppressed field names. */
448  /***************************************************************************/
449  dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
450  while (dlist_item != NULL)
451  {
452  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs = dlist_item->item;
453  ENTRY hash_add;
454 
455  /*************************************************************************/
456  /* Set the key to the string, and the item to the nv_pairs. */
457  /*************************************************************************/
458  assert(nv_pairs != NULL);
459  hash_add.key = nv_pairs->nv_pair_field_name;
460  hash_add.data = nv_pairs;
461  hsearch_r(hash_add, ENTER, &add_result, throttle_spec->hash_nv_pairs_list);
462 
463  /*************************************************************************/
464  /* Create the nv_pair_names hash since we're in here. */
465  /*************************************************************************/
466  nv_pairs->hash_nv_pair_names =
467  evel_throttle_hash_create(&nv_pairs->suppressed_nv_pair_names);
468 
469  dlist_item = dlist_get_next(dlist_item);
470  }
471 
472  EVEL_EXIT();
473 }
474 
475 /**************************************************************************/
481 struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys)
482 {
483  int key_count;
484  struct hsearch_data * hash_table;
485  ENTRY * add_result;
486 
487  EVEL_ENTER();
488 
489  /***************************************************************************/
490  /* Check preconditions. */
491  /***************************************************************************/
492  assert(hash_keys != NULL);
493 
494  /***************************************************************************/
495  /* Count the keys and if there are any, populate the hash table with them. */
496  /***************************************************************************/
497  key_count = dlist_count(hash_keys);
498  if (key_count > 0)
499  {
500  EVEL_DEBUG("Populating table for %d keys", key_count);
501 
502  hash_table = calloc(1, sizeof(struct hsearch_data));
503  assert(hash_table != NULL);
504 
505  /*************************************************************************/
506  /* We need to leave plenty of space in the table - see hcreate_r notes. */
507  /*************************************************************************/
508  if (hcreate_r(key_count * 2, hash_table) != 0)
509  {
511  dlist_item = dlist_get_first(hash_keys);
512  while (dlist_item != NULL)
513  {
514  assert(dlist_item->item != NULL);
515 
516  /*********************************************************************/
517  /* Set the key and data to the item, which is a string in this case. */
518  /*********************************************************************/
519  ENTRY hash_add;
520  hash_add.key = dlist_item->item;
521  hash_add.data = dlist_item->item;
522  hsearch_r(hash_add, ENTER, &add_result, hash_table);
523  dlist_item = dlist_get_next(dlist_item);
524  }
525  }
526  else
527  {
528  EVEL_ERROR("Failed to create hash table");
529  free(hash_table);
530  hash_table = NULL;
531  }
532  }
533  else
534  {
535  hash_table = NULL;
536  }
537 
538  EVEL_EXIT();
539 
540  return hash_table;
541 }
542 
543 /**************************************************************************/
548 void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec)
549 {
550  char * field_name;
551  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
552 
553  EVEL_ENTER();
554 
555  /***************************************************************************/
556  /* Check preconditions. */
557  /***************************************************************************/
558  assert(throttle_spec != NULL);
559 
560  /***************************************************************************/
561  /* Free any hash tables. */
562  /***************************************************************************/
563  if (throttle_spec->hash_field_names != NULL)
564  {
565  hdestroy_r(throttle_spec->hash_field_names);
566  free(throttle_spec->hash_field_names);
567  }
568  if (throttle_spec->hash_nv_pairs_list != NULL)
569  {
570  hdestroy_r(throttle_spec->hash_nv_pairs_list);
571  free(throttle_spec->hash_nv_pairs_list);
572  }
573 
574  /***************************************************************************/
575  /* Iterate through the linked lists, freeing memory. */
576  /***************************************************************************/
577  field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
578  while (field_name != NULL)
579  {
580  free(field_name);
581  field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
582  }
583 
584  nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
585  while (nv_pairs != NULL)
586  {
587  evel_throttle_free_nv_pair(nv_pairs);
588  nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
589  }
590 
591  free(throttle_spec);
592 
593  EVEL_EXIT();
594 }
595 
596 /**************************************************************************/
601 void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
602 {
603  char * suppressed_name;
604 
605  EVEL_ENTER();
606 
607  /***************************************************************************/
608  /* Check preconditions. */
609  /***************************************************************************/
610  assert(nv_pairs != NULL);
611 
612  /***************************************************************************/
613  /* Free any hash tables. */
614  /***************************************************************************/
615  if (nv_pairs->hash_nv_pair_names != NULL)
616  {
617  hdestroy_r(nv_pairs->hash_nv_pair_names);
618  free(nv_pairs->hash_nv_pair_names);
619  }
620 
621  /***************************************************************************/
622  /* Iterate through the linked lists, freeing memory. */
623  /***************************************************************************/
624  suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
625  while (suppressed_name != NULL)
626  {
627  free(suppressed_name);
628  suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
629  }
630  if (nv_pairs->nv_pair_field_name != NULL)
631  {
632  free(nv_pairs->nv_pair_field_name);
633  }
634  free(nv_pairs);
635 
636  EVEL_EXIT();
637 }
638 
639 /**************************************************************************/
648 bool evel_handle_command_list(const MEMORY_CHUNK * const chunk,
649  const jsmntok_t * const json_tokens,
650  const int num_tokens,
651  MEMORY_CHUNK * const post)
652 {
653  EVEL_JSON_STACK stack;
654  EVEL_JSON_STACK * json_stack = &stack;
655  EVEL_JSON_STACK_ENTRY * entry;
656 
657  bool json_ok = true;
658  int token_index = 0;
659 
660  EVEL_ENTER();
661 
662  /***************************************************************************/
663  /* Check preconditions. */
664  /***************************************************************************/
665  assert(chunk != NULL);
666  assert(json_tokens != NULL);
667  assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS);
668 
669  /***************************************************************************/
670  /* Collect one top-level item. */
671  /***************************************************************************/
672  evel_init_json_stack(json_stack, chunk);
673 
674  /***************************************************************************/
675  /* Initialize JSON processing variables. */
676  /***************************************************************************/
677  evel_provide_throttling_state = false;
678  evel_command_type_value = NULL;
679  evel_measurement_interval_value = NULL;
680  evel_throttle_spec_domain_value = NULL;
681  evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
682  evel_temp_throttle = NULL;
684 
685  /***************************************************************************/
686  /* Loop through the tokens, keeping a stack of state representing the */
687  /* nested JSON structure (see json_state). We also track our way through */
688  /* the ::EVEL_JSON_COMMAND_STATE as we go. */
689  /***************************************************************************/
690  while (json_ok && (token_index < num_tokens))
691  {
692  const jsmntok_t * const token = &json_tokens[token_index];
693 
694  if (EVEL_DEBUG_ON())
695  {
696  evel_debug_token(chunk, token);
697  }
698 
699  /*************************************************************************/
700  /* We may have popped or pushed, so always re-evaluate the stack entry. */
701  /*************************************************************************/
702  entry = &json_stack->entry[json_stack->level];
703 
704  switch(token->type)
705  {
706  case JSMN_OBJECT:
707  if ((entry->json_state == EVEL_JSON_ITEM) ||
708  (entry->json_state == EVEL_JSON_VALUE))
709  {
710  json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_KEY);
711  }
712  else
713  {
714  EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
715  entry->json_state, token_index, token->type);
716  json_ok = false;
717  }
718  break;
719 
720  case JSMN_ARRAY:
721  if ((entry->json_state == EVEL_JSON_ITEM) ||
722  (entry->json_state == EVEL_JSON_VALUE))
723  {
724  json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_ITEM);
725  }
726  else
727  {
728  EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
729  entry->json_state, token_index, token->type);
730  json_ok = false;
731  }
732  break;
733 
734  case JSMN_STRING:
735  if (entry->json_state == EVEL_JSON_KEY)
736  {
737  evel_stack_store_key(json_stack, token);
738  }
739  else if (entry->json_state == EVEL_JSON_VALUE)
740  {
741  evel_stack_store_value(json_stack, token);
742  }
743  else if (entry->json_state == EVEL_JSON_ITEM)
744  {
745  evel_stack_store_item(json_stack, token);
746  }
747  else
748  {
749  EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
750  entry->json_state, token_index, token->type);
751  json_ok = false;
752  }
753  break;
754 
755  case JSMN_PRIMITIVE:
756  if (entry->json_state == EVEL_JSON_VALUE)
757  {
758  evel_stack_store_value(json_stack, token);
759  }
760  else if (entry->json_state == EVEL_JSON_ITEM)
761  {
762  evel_stack_store_item(json_stack, token);
763  }
764  else
765  {
766  EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
767  entry->json_state, token_index, token->type);
768  json_ok = false;
769  }
770  break;
771 
772  case JSMN_UNDEFINED:
773  default:
774  EVEL_ERROR("Unexpected JSON format at token %d (%d)",
775  token_index, token->type);
776  json_ok = false;
777  break;
778  }
779 
780  /*************************************************************************/
781  /* Pop the stack if we're counted enough nested items. */
782  /*************************************************************************/
783  evel_stack_pop(json_stack);
784 
785  token_index++;
786  }
787 
788  /***************************************************************************/
789  /* Cleanup the stack - we may have exited without winding it back, if the */
790  /* input was not well formed. */
791  /***************************************************************************/
792  evel_stack_cleanup(json_stack);
793 
794  /***************************************************************************/
795  /* We may want to generate and POST a response to the command list. */
796  /***************************************************************************/
797  if (json_ok)
798  {
799  evel_command_list_response(post);
800  }
801 
802  /***************************************************************************/
803  /* Make sure we're clean on exit. */
804  /***************************************************************************/
805  assert(evel_command_type_value == NULL);
806  assert(evel_measurement_interval_value == NULL);
807  assert(evel_throttle_spec_domain_value == NULL);
808  assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
809  assert(evel_temp_throttle == NULL);
810 
811  EVEL_EXIT();
812 
813  return json_ok;
814 }
815 
816 /**************************************************************************/
825 char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
826  const jsmntok_t * const token)
827 {
828  char temp_char;
829  char * result;
830 
831  EVEL_ENTER();
832 
833  /***************************************************************************/
834  /* Call strdup to copy the string, inserting a temporary \0 for the call. */
835  /***************************************************************************/
836  temp_char = chunk->memory[token->end];
837  chunk->memory[token->end] = '\0';
838  result = strdup(chunk->memory + token->start);
839  assert(result != NULL);
840  chunk->memory[token->end] = temp_char;
841 
842  EVEL_EXIT();
843 
844  return result;
845 }
846 
847 /**************************************************************************/
853 void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
854  const MEMORY_CHUNK * const chunk)
855 {
856  EVEL_JSON_STACK_ENTRY * entry;
857 
858  EVEL_ENTER();
859 
860  json_stack->level = 0;
861  entry = json_stack->entry;
862  entry->json_state = EVEL_JSON_ITEM;
863  entry->json_count = 0;
864  entry->num_required = 1;
865  entry->json_key = NULL;
866  json_stack->chunk = chunk;
867 
868  EVEL_EXIT();
869 }
870 
871 /**************************************************************************/
879 bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
880  const int num_required,
881  const EVEL_JSON_STATE new_state)
882 {
883  EVEL_JSON_STACK_ENTRY * entry;
884  char * key;
885  bool result;
886 
887  EVEL_ENTER();
888 
889  /***************************************************************************/
890  /* Check preconditions. */
891  /***************************************************************************/
892  assert(json_stack != NULL);
893  assert(json_stack->level >= 0);
894  assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
895  assert((new_state == EVEL_JSON_ITEM) || (new_state == EVEL_JSON_KEY));
896 
897  /***************************************************************************/
898  /* Check nesting depth, and stop processing if we hit the limit. */
899  /***************************************************************************/
900  if ((json_stack->level + 1) >= EVEL_JSON_STACK_DEPTH)
901  {
902  EVEL_ERROR("JSON Nesting is too deep - stop processing");
903  result = false;
904  goto exit_label;
905  }
906 
907  /***************************************************************************/
908  /* Evaluate cases where we recurse and are interested in the contents. */
909  /***************************************************************************/
910  entry = &json_stack->entry[json_stack->level];
911  key = entry->json_key;
912 
913  /***************************************************************************/
914  /* Note that this is the key before we drop a level. */
915  /***************************************************************************/
916  if (key != NULL)
917  {
918  EVEL_DEBUG("Push with key: %s", key);
919 
920  switch (evel_json_command_state)
921  {
922  case EVEL_JCS_START:
923  if (strcmp(key, "commandList") == 0)
924  {
925  evel_set_command_state(EVEL_JCS_COMMAND_LIST);
926  }
927  break;
928 
930  if (strcmp(key, "command") == 0)
931  {
932  evel_open_command();
933  evel_set_command_state(EVEL_JCS_COMMAND);
934  }
935  break;
936 
937  case EVEL_JCS_COMMAND:
938  if (strcmp(key, "eventDomainThrottleSpecification") == 0)
939  {
940  evel_open_throttle_spec();
941  evel_set_command_state(EVEL_JCS_SPEC);
942  }
943  break;
944 
945  case EVEL_JCS_SPEC:
946  if (strcmp(key, "suppressedFieldNames") == 0)
947  {
948  evel_set_command_state(EVEL_JCS_FIELD_NAMES);
949  }
950  else if (strcmp(key, "suppressedNvPairsList") == 0)
951  {
952  evel_set_command_state(EVEL_JCS_PAIRS_LIST);
953  }
954  break;
955 
957  if (strcmp(key, "suppressedNvPairNames") == 0)
958  {
959  evel_set_command_state(EVEL_JCS_NV_PAIR_NAMES);
960  }
961  break;
962 
964  case EVEL_JCS_PAIRS_LIST:
966  default:
967  EVEL_ERROR("Unexpected JSON key %s in state %d",
968  key,
970  break;
971  }
972  }
973  else
974  {
975  EVEL_DEBUG("Push with no key");
976 
977  /*************************************************************************/
978  /* If we're pushing without a key, then we're in an array. We switch */
979  /* state based on the existing state and stack level. */
980  /*************************************************************************/
981  const int COMMAND_LIST_LEVEL = 2;
982  const int NV_PAIRS_LIST_LEVEL = 6;
983 
985  (json_stack->level == NV_PAIRS_LIST_LEVEL))
986  {
987  /***********************************************************************/
988  /* We are entering an object within the "suppressedNvPairsList" array. */
989  /***********************************************************************/
990  evel_open_nv_pairs_list_entry();
991  evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
992  }
993 
995  (json_stack->level == COMMAND_LIST_LEVEL))
996  {
997  /***********************************************************************/
998  /* We are entering an object within the "commandList" array. */
999  /***********************************************************************/
1000  evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
1001  }
1002  }
1003 
1004  /***************************************************************************/
1005  /* Push the stack and initialize the entry. */
1006  /***************************************************************************/
1007  json_stack->level++;
1008  entry++;
1009  EVEL_DEBUG("Stack Push -> %d", json_stack->level);
1010  entry = &json_stack->entry[json_stack->level];
1011  entry->json_count = 0;
1012  entry->num_required = num_required;
1013  entry->json_state = new_state;
1014  entry->json_key = NULL;
1015  result = true;
1016 
1017 exit_label:
1018 
1019  EVEL_EXIT();
1020 
1021  return result;
1022 }
1023 
1024 /**************************************************************************/
1029 void evel_stack_pop(EVEL_JSON_STACK * const json_stack)
1030 {
1031  EVEL_JSON_STACK_ENTRY * entry;
1032  char * key;
1033 
1034  EVEL_ENTER();
1035 
1036  /***************************************************************************/
1037  /* Check preconditions. */
1038  /***************************************************************************/
1039  assert(json_stack != NULL);
1040  assert(json_stack->level >= 0);
1041  assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1042 
1043  entry = &json_stack->entry[json_stack->level];
1044  while ((json_stack->level > 0) && (entry->json_count == entry->num_required))
1045  {
1046  key = entry->json_key;
1047 
1048  switch (evel_json_command_state)
1049  {
1050  case EVEL_JCS_COMMAND_LIST:
1051  evel_set_command_state(EVEL_JCS_START);
1052  break;
1053 
1055  evel_set_command_state(EVEL_JCS_COMMAND_LIST);
1056  break;
1057 
1058  case EVEL_JCS_COMMAND:
1059  evel_close_command();
1060  evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
1061  break;
1062 
1063  case EVEL_JCS_SPEC:
1064  evel_close_throttle_spec();
1065  evel_set_command_state(EVEL_JCS_COMMAND);
1066  break;
1067 
1068  case EVEL_JCS_FIELD_NAMES:
1069  evel_set_command_state(EVEL_JCS_SPEC);
1070  break;
1071 
1072  case EVEL_JCS_PAIRS_LIST:
1073  evel_set_command_state(EVEL_JCS_SPEC);
1074  break;
1075 
1077  evel_close_nv_pairs_list_entry();
1078  evel_set_command_state(EVEL_JCS_PAIRS_LIST);
1079  break;
1080 
1082  evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
1083  break;
1084 
1085  default:
1086  break;
1087  }
1088 
1089  /*************************************************************************/
1090  /* Free off any key that was duplicated and stored. */
1091  /*************************************************************************/
1092  if (key != NULL)
1093  {
1094  free(key);
1095  entry->json_key = NULL;
1096  }
1097 
1098  /*************************************************************************/
1099  /* We just reached the required number of key-value pairs or items, so */
1100  /* pop the stack. */
1101  /*************************************************************************/
1102  json_stack->level--;
1103  entry--;
1104 
1105  EVEL_DEBUG("Stack Pop -> %d", json_stack->level);
1106 
1107  /*************************************************************************/
1108  /* We just completed collection of an ITEM (within an ARRAY) or a VALUE */
1109  /* (within an OBJECT). Either way, we need to count it. */
1110  /*************************************************************************/
1111  entry->json_count++;
1112 
1113  /*************************************************************************/
1114  /* If we just completed a VALUE, then we expect the next element to be a */
1115  /* key, if there is a next element. */
1116  /*************************************************************************/
1117  if (entry->json_state == EVEL_JSON_VALUE)
1118  {
1119  entry->json_state = EVEL_JSON_KEY;
1120  }
1121  }
1122 
1123  EVEL_EXIT();
1124 }
1125 
1126 /**************************************************************************/
1131 void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack)
1132 {
1133  EVEL_JSON_STACK_ENTRY * entry;
1134 
1135  EVEL_ENTER();
1136 
1137  /***************************************************************************/
1138  /* Check preconditions. */
1139  /***************************************************************************/
1140  assert(json_stack != NULL);
1141  assert(json_stack->level >= 0);
1142  assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1143 
1144  entry = &json_stack->entry[json_stack->level];
1145  while ((json_stack->level > 0))
1146  {
1147  /*************************************************************************/
1148  /* Free off any key that was duplicated and stored. */
1149  /*************************************************************************/
1150  if (entry->json_key != NULL)
1151  {
1152  free(entry->json_key);
1153  entry->json_key = NULL;
1154  }
1155 
1156  /*************************************************************************/
1157  /* We just reached the required number of key-value pairs or items, so */
1158  /* pop the stack. */
1159  /*************************************************************************/
1160  json_stack->level--;
1161  entry--;
1162  }
1163 
1164  /***************************************************************************/
1165  /* If we hit EVEL_JSON_STACK_DEPTH, we exit the loop and can leave these */
1166  /* values hanging - so clean them up. */
1167  /***************************************************************************/
1168  if (evel_command_type_value != NULL)
1169  {
1170  free(evel_command_type_value);
1171  evel_command_type_value = NULL;
1172  }
1173  if (evel_measurement_interval_value != NULL)
1174  {
1175  free(evel_measurement_interval_value);
1176  evel_measurement_interval_value = NULL;
1177  }
1178  if (evel_throttle_spec_domain_value != NULL)
1179  {
1180  free(evel_throttle_spec_domain_value);
1181  evel_throttle_spec_domain_value = NULL;
1182  }
1183  evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1184  if (evel_temp_throttle != NULL)
1185  {
1186  evel_throttle_free(evel_temp_throttle);
1187  evel_temp_throttle = NULL;
1188  }
1189 
1190  EVEL_EXIT();
1191 }
1192 
1193 /**************************************************************************/
1201 void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
1202  const jsmntok_t * const token)
1203 {
1204  EVEL_JSON_STACK_ENTRY * entry;
1205 
1206  EVEL_ENTER();
1207 
1208  /***************************************************************************/
1209  /* Check preconditions. */
1210  /***************************************************************************/
1211  assert(json_stack != NULL);
1212  assert(json_stack->level >= 0);
1213  assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1214 
1215  /***************************************************************************/
1216  /* Free any previously stored key, replacing it with the new one. */
1217  /***************************************************************************/
1218  entry = &json_stack->entry[json_stack->level];
1219  if (entry->json_key != NULL)
1220  {
1221  free(entry->json_key);
1222  }
1223  entry->json_key = evel_stack_strdup(json_stack->chunk, token);
1224 
1225  /***************************************************************************/
1226  /* Switch state to collecting the corresponding value. */
1227  /***************************************************************************/
1228  entry->json_state = EVEL_JSON_VALUE;
1229 
1230  EVEL_DEBUG("Stored key: %s", entry->json_key);
1231  EVEL_EXIT();
1232 }
1233 
1234 /**************************************************************************/
1240 void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
1241  const jsmntok_t * const token)
1242 {
1243  EVEL_JSON_STACK_ENTRY * entry;
1244  char * value;
1245  bool stored;
1246 
1247  EVEL_ENTER();
1248 
1249  /***************************************************************************/
1250  /* Check preconditions. */
1251  /***************************************************************************/
1252  assert(json_stack != NULL);
1253  assert(json_stack->level >= 0);
1254  assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1255 
1256  /***************************************************************************/
1257  /* Based on the (key, state), work out whether we're expecting a value, */
1258  /* then store or ignore it as required. */
1259  /***************************************************************************/
1260  entry = &json_stack->entry[json_stack->level];
1261  value = evel_stack_strdup(json_stack->chunk, token);
1262  stored = false;
1263  EVEL_DEBUG("Store value: %s", value);
1264 
1265  switch (evel_json_command_state)
1266  {
1267  case EVEL_JCS_COMMAND:
1268  if (strcmp(entry->json_key, "commandType") == 0)
1269  {
1270  evel_command_type_value = value;
1271  stored = true;
1272  }
1273  else if (strcmp(entry->json_key, "measurementInterval") == 0)
1274  {
1275  evel_measurement_interval_value = value;
1276  stored = true;
1277  }
1278  break;
1279 
1280  case EVEL_JCS_SPEC:
1281  if (strcmp(entry->json_key, "eventDomain") == 0)
1282  {
1283  evel_throttle_spec_domain_value = value;
1284  stored = true;
1285  }
1286  break;
1287 
1289  if (strcmp(entry->json_key, "nvPairFieldName") == 0)
1290  {
1291  evel_store_nv_pair_field_name(value);
1292  stored = true;
1293  }
1294  break;
1295 
1296  default:
1297  EVEL_DEBUG("Ignoring value in state: %s",
1298  evel_jcs_strings[evel_json_command_state]);
1299  break;
1300  }
1301 
1302  if (!stored)
1303  {
1304  EVEL_DEBUG("Ignored value: %s", value);
1305  free(value);
1306  }
1307 
1308  /***************************************************************************/
1309  /* Switch state to another key. */
1310  /***************************************************************************/
1311  entry->json_state = EVEL_JSON_KEY;
1312 
1313  /***************************************************************************/
1314  /* Count the key-value pair. */
1315  /***************************************************************************/
1316  entry->json_count++;
1317 
1318  EVEL_EXIT();
1319 }
1320 
1321 /**************************************************************************/
1327 void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
1328  const jsmntok_t * const token)
1329 {
1330  EVEL_JSON_STACK_ENTRY * entry;
1331  char * item;
1332  bool stored;
1333 
1334  EVEL_ENTER();
1335 
1336  /***************************************************************************/
1337  /* Check preconditions. */
1338  /***************************************************************************/
1339  assert(json_stack != NULL);
1340  assert(json_stack->level >= 0);
1341  assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
1342 
1343  /***************************************************************************/
1344  /* Based on the state, work out whether we're expecting an item, then */
1345  /* store or ignore it as required. */
1346  /***************************************************************************/
1347  entry = &json_stack->entry[json_stack->level];
1348  item = evel_stack_strdup(json_stack->chunk, token);
1349  stored = false;
1350  EVEL_DEBUG("Store item: %s", item);
1351 
1352  switch (evel_json_command_state)
1353  {
1355  evel_store_nv_pair_name(item);
1356  stored = true;
1357  break;
1358 
1359  case EVEL_JCS_FIELD_NAMES:
1360  evel_store_suppressed_field_name(item);
1361  stored = true;
1362  break;
1363 
1364  default:
1365  EVEL_DEBUG("Ignoring item in state: %s",
1366  evel_jcs_strings[evel_json_command_state]);
1367  break;
1368  }
1369 
1370  if (!stored)
1371  {
1372  EVEL_DEBUG("Ignored item: %s", item);
1373  free(item);
1374  }
1375 
1376  /***************************************************************************/
1377  /* We need another item. This is purely defensive. */
1378  /***************************************************************************/
1379  entry->json_state = EVEL_JSON_ITEM;
1380 
1381  /***************************************************************************/
1382  /* Count the item. */
1383  /***************************************************************************/
1384  entry->json_count++;
1385 }
1386 
1387 /**************************************************************************/
1392 void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state)
1393 {
1394  EVEL_ENTER();
1395 
1396  /***************************************************************************/
1397  /* Check preconditions. */
1398  /***************************************************************************/
1400  assert(new_state < EVEL_JCS_MAX);
1401 
1402  /***************************************************************************/
1403  /* Provide common debug, and set the new state. */
1404  /***************************************************************************/
1405  EVEL_DEBUG("Command State: %s -> %s",
1406  evel_jcs_strings[evel_json_command_state],
1407  evel_jcs_strings[new_state]);
1408  evel_json_command_state = new_state;
1409 
1410  EVEL_EXIT();
1411 }
1412 
1413 /**************************************************************************/
1419 void evel_debug_token(const MEMORY_CHUNK * const chunk,
1420  const jsmntok_t * const token)
1421 {
1422  char temp_char;
1423 
1424  EVEL_ENTER();
1425 
1426  /***************************************************************************/
1427  /* Check preconditions. */
1428  /***************************************************************************/
1429  assert(token->type > 0);
1430  assert(token->type < JSON_TOKEN_TYPES);
1431 
1432  /***************************************************************************/
1433  /* Log the token, leaving it in the state in which it started. */
1434  /***************************************************************************/
1435  temp_char = chunk->memory[token->end];
1436  chunk->memory[token->end] = '\0';
1437  EVEL_DEBUG("JSON token type: %s", evel_json_token_strings[token->type]);
1438  EVEL_DEBUG("JSON token: %s", chunk->memory + token->start);
1439  chunk->memory[token->end] = temp_char;
1440 
1441  EVEL_EXIT();
1442 }
1443 
1444 /**************************************************************************/
1449 void evel_command_list_response(MEMORY_CHUNK * const post)
1450 {
1451  char * json_post;
1452 
1453  EVEL_ENTER();
1454 
1455  /***************************************************************************/
1456  /* Check preconditions. */
1457  /***************************************************************************/
1458  assert(post != NULL);
1459  assert(post->memory == NULL);
1460 
1461  if (evel_provide_throttling_state)
1462  {
1463  EVEL_DEBUG("Provide throttling state");
1464 
1465  /*************************************************************************/
1466  /* Encode the response, making it printf-able for debug. */
1467  /*************************************************************************/
1468  json_post = malloc(EVEL_MAX_JSON_BODY);
1469  assert(json_post != NULL);
1470  post->size = evel_json_encode_throttle(json_post, EVEL_MAX_JSON_BODY - 1);
1471  post->memory = json_post;
1472  post->memory[post->size] = '\0';
1473  evel_provide_throttling_state = false;
1474  }
1475 
1476  EVEL_EXIT();
1477 }
1478 
1479 /**************************************************************************/
1486 int evel_json_encode_throttle(char * const json, const int max_size)
1487 {
1488  bool throttled;
1489  int domain;
1490  int offset;
1491  bool domain_added;
1492 
1493  EVEL_ENTER();
1494 
1495  /***************************************************************************/
1496  /* Check preconditions. */
1497  /***************************************************************************/
1498  assert(json != NULL);
1499  assert(max_size > 0);
1500 
1501  /***************************************************************************/
1502  /* Work out if we're throttled. */
1503  /***************************************************************************/
1504  throttled = false;
1505  for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1506  {
1507  if (evel_throttle_spec[domain] != NULL)
1508  {
1509  throttled = true;
1510  }
1511  }
1512 
1513  /***************************************************************************/
1514  /* Encode the response. */
1515  /***************************************************************************/
1516  offset = 0;
1517  offset += snprintf(json + offset, max_size - offset,
1518  "{\"eventThrottlingState\": {");
1519  offset += snprintf(json + offset, max_size - offset,
1520  "\"eventThrottlingMode\": \"%s\"",
1521  throttled ? "throttled" : "normal");
1522  if (throttled)
1523  {
1524  offset += snprintf(json + offset, max_size - offset,
1525  ", \"eventDomainThrottleSpecificationList\": [");
1526 
1527  domain_added = false;
1528  for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
1529  {
1530  if (evel_throttle_spec[domain] != NULL)
1531  {
1532  if (domain_added)
1533  {
1534  offset += snprintf(json + offset, max_size - offset, ", ");
1535  }
1536 
1537  offset += evel_json_encode_throttle_spec(json + offset,
1538  max_size - offset,
1539  domain);
1540  domain_added = true;
1541  }
1542  }
1543 
1544  offset += snprintf(json + offset, max_size - offset, "]");
1545  }
1546 
1547  offset += snprintf(json + offset, max_size - offset, "}}");
1548 
1549  EVEL_EXIT();
1550 
1551  return offset;
1552 }
1553 
1554 /**************************************************************************/
1561 int evel_json_encode_throttle_spec(char * const json,
1562  const int max_size,
1563  const EVEL_EVENT_DOMAINS domain)
1564 {
1565  int offset;
1566  EVEL_THROTTLE_SPEC * throttle_spec;
1568  EVEL_ENTER();
1569 
1570  /***************************************************************************/
1571  /* Check preconditions. */
1572  /***************************************************************************/
1573  assert(domain >= EVEL_DOMAIN_FAULT);
1574  assert(domain < EVEL_MAX_DOMAINS);
1575  assert(evel_throttle_spec[domain] != NULL);
1576 
1577  throttle_spec = evel_throttle_spec[domain];
1578 
1579  /***************************************************************************/
1580  /* Encode the domain. */
1581  /***************************************************************************/
1582  offset = 0;
1583  offset += snprintf(json + offset, max_size - offset,
1584  "{");
1585  offset += snprintf(json + offset, max_size - offset,
1586  "\"eventDomain\": \"%s\"",
1587  evel_domain_strings[domain]);
1588 
1589  /***************************************************************************/
1590  /* Encode "suppressedFieldNames". */
1591  /***************************************************************************/
1592  dlist_item = dlist_get_first(&throttle_spec->suppressed_field_names);
1593  if (dlist_item != NULL)
1594  {
1595  offset += snprintf(json + offset, max_size - offset,
1596  ", \"suppressedFieldNames\": [");
1597  while (dlist_item != NULL)
1598  {
1599  char * suppressed_field = dlist_item->item;
1600  assert(suppressed_field != NULL);
1601 
1602  offset += snprintf(json + offset, max_size - offset,
1603  "\"%s\"", suppressed_field);
1604  dlist_item = dlist_get_next(dlist_item);
1605  if (dlist_item != NULL)
1606  {
1607  offset += snprintf(json + offset, max_size - offset, ", ");
1608  }
1609  }
1610 
1611  offset += snprintf(json + offset, max_size - offset, "]");
1612  }
1613 
1614  /***************************************************************************/
1615  /* Encode "suppressedNvPairsList". */
1616  /***************************************************************************/
1617  dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
1618  if (dlist_item != NULL)
1619  {
1620  offset += snprintf(json + offset, max_size - offset,
1621  ", \"suppressedNvPairsList\": [");
1622  while (dlist_item != NULL)
1623  {
1624  offset += evel_json_encode_nv_pairs(json + offset,
1625  max_size - offset,
1626  dlist_item->item);
1627  dlist_item = dlist_get_next(dlist_item);
1628  if (dlist_item != NULL)
1629  {
1630  offset += snprintf(json + offset, max_size - offset, ", ");
1631  }
1632  }
1633 
1634  offset += snprintf(json + offset, max_size - offset, "]");
1635  }
1636 
1637  offset += snprintf(json + offset, max_size - offset, "}");
1638 
1639  EVEL_EXIT();
1640 
1641  return offset;
1642 }
1643 
1644 /**************************************************************************/
1651 int evel_json_encode_nv_pairs(char * const json,
1652  const int max_size,
1653  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
1654 {
1656  char * name;
1657  int offset;
1658 
1659  /***************************************************************************/
1660  /* Check preconditions. */
1661  /***************************************************************************/
1662  assert(nv_pairs != NULL);
1663  assert(nv_pairs->nv_pair_field_name != NULL);
1664  assert(!dlist_is_empty(&nv_pairs->suppressed_nv_pair_names));
1665 
1666  /***************************************************************************/
1667  /* Encode it. */
1668  /***************************************************************************/
1669  offset = 0;
1670  offset += snprintf(json + offset, max_size - offset, "{");
1671  offset += snprintf(json + offset, max_size - offset,
1672  "\"nvPairFieldName\": \"%s\"",
1673  nv_pairs->nv_pair_field_name);
1674  dlist_item = dlist_get_first(&nv_pairs->suppressed_nv_pair_names);
1675  offset += snprintf(json + offset, max_size - offset,
1676  ", \"suppressedNvPairNames\": [");
1677  while (dlist_item != NULL)
1678  {
1679  name = dlist_item->item;
1680  assert(name != NULL);
1681  offset += snprintf(json + offset, max_size - offset, "\"%s\"", name);
1682  dlist_item = dlist_get_next(dlist_item);
1683  if (dlist_item != NULL)
1684  {
1685  offset += snprintf(json + offset, max_size - offset, ", ");
1686  }
1687  }
1688  offset += snprintf(json + offset, max_size - offset, "]");
1689  offset += snprintf(json + offset, max_size - offset, "}");
1690 
1691  EVEL_EXIT();
1692 
1693  return offset;
1694 }
1695 
1696 /**************************************************************************/
1699 void evel_open_command()
1700 {
1701  EVEL_ENTER();
1702 
1703  /***************************************************************************/
1704  /* Make some assertions. */
1705  /***************************************************************************/
1706  assert(evel_command_type_value == NULL);
1707  assert(evel_measurement_interval_value == NULL);
1708 
1709  EVEL_EXIT();
1710 }
1711 
1712 /**************************************************************************/
1715 void evel_close_command()
1716 {
1717  EVEL_ENTER();
1718 
1719  /***************************************************************************/
1720  /* If a commandType was provided, fan out and handle it now what we have */
1721  /* fathered all related information. */
1722  /* */
1723  /* Note that we handle throttling specification and measurement interval */
1724  /* updates immediately on closing the command (not the list). We could */
1725  /* reject *all* commands in a list if any of them are invalid, but we are */
1726  /* take a best-effort strategy here - any valid-looking command gets */
1727  /* implemented regardless of what follows. */
1728  /***************************************************************************/
1729  if (evel_command_type_value != NULL)
1730  {
1731  EVEL_DEBUG("Closing command %s", evel_command_type_value);
1732 
1733  if (strcmp(evel_command_type_value, "provideThrottlingState") == 0)
1734  {
1735  evel_provide_throttling_state = true;
1736  }
1737  else if (strcmp(evel_command_type_value, "throttlingSpecification") == 0)
1738  {
1739  evel_set_throttling_spec();
1740  }
1741  else if (strcmp(evel_command_type_value, "measurementIntervalChange") == 0)
1742  {
1743  evel_set_measurement_interval();
1744  }
1745  else
1746  {
1747  EVEL_ERROR("Ignoring unknown commandType: %s\n",
1748  evel_command_type_value);
1749  }
1750 
1751  /*************************************************************************/
1752  /* Free the captured "commandType" value. */
1753  /*************************************************************************/
1754  free(evel_command_type_value);
1755  evel_command_type_value = NULL;
1756  }
1757 
1758  /***************************************************************************/
1759  /* There could be an unused working throttle spec at this point - if the */
1760  /* "throttlingSpecification" commandType was not provided, or an invalid */
1761  /* domain was provided, or was not provided at all. */
1762  /***************************************************************************/
1763  if (evel_temp_throttle != NULL)
1764  {
1765  evel_throttle_free(evel_temp_throttle);
1766  evel_temp_throttle = NULL;
1767  }
1768 
1769  /***************************************************************************/
1770  /* Similarly, the domain could be set. */
1771  /***************************************************************************/
1772  evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
1773 
1774  /***************************************************************************/
1775  /* There could be an unused measurement interval value at this point - if */
1776  /* the "measurementIntervalChange" command was not provided. */
1777  /***************************************************************************/
1778  if (evel_measurement_interval_value != NULL)
1779  {
1780  free(evel_measurement_interval_value);
1781  evel_measurement_interval_value = NULL;
1782  }
1783 
1784  EVEL_EXIT();
1785 }
1786 
1787 /**************************************************************************/
1790 void evel_set_throttling_spec()
1791 {
1792  EVEL_ENTER();
1793 
1794  if ((evel_throttle_spec_domain >= 0) &&
1795  (evel_throttle_spec_domain < EVEL_MAX_DOMAINS))
1796  {
1797  EVEL_DEBUG("Updating throttle spec for domain: %s",
1798  evel_domain_strings[evel_throttle_spec_domain]);
1799 
1800  /*************************************************************************/
1801  /* Free off the previous throttle specification for the domain, if there */
1802  /* is one. */
1803  /*************************************************************************/
1804  if (evel_throttle_spec[evel_throttle_spec_domain] != NULL)
1805  {
1806  evel_throttle_free(evel_throttle_spec[evel_throttle_spec_domain]);
1807  }
1808 
1809  /*************************************************************************/
1810  /* Finalize the working throttling spec, if there is one. */
1811  /*************************************************************************/
1812  if (evel_temp_throttle != NULL)
1813  {
1814  evel_throttle_finalize(evel_temp_throttle);
1815  }
1816 
1817  /*************************************************************************/
1818  /* Replace the throttle specification for the domain with the working */
1819  /* throttle specification. This could be NULL, if an empty throttle */
1820  /* specification has been received for a domain. */
1821  /*************************************************************************/
1822  evel_throttle_spec[evel_throttle_spec_domain] = evel_temp_throttle;
1823  evel_temp_throttle = NULL;
1824  }
1825 
1826  EVEL_EXIT();
1827 }
1828 
1829 /**************************************************************************/
1832 void evel_set_measurement_interval()
1833 {
1834  EVEL_ENTER();
1835 
1836  if (evel_measurement_interval_value != NULL)
1837  {
1838  const long int value = strtol(evel_measurement_interval_value, NULL, 10);
1839 
1840  if ((value >= 0) && (value <= INT_MAX))
1841  {
1842  /***********************************************************************/
1843  /* Lock, update, unlock. */
1844  /***********************************************************************/
1845  EVEL_DEBUG("Updating measurement interval to %d\n", value);
1846 
1847  pthread_mutex_lock(&evel_measurement_interval_mutex);
1848  evel_measurement_interval = value;
1849  pthread_mutex_unlock(&evel_measurement_interval_mutex);
1850  }
1851  else
1852  {
1853  EVEL_ERROR("Ignoring invalid measurement interval: %s",
1854  evel_measurement_interval_value);
1855  }
1856  }
1857 
1858  EVEL_EXIT();
1859 }
1860 
1861 /**************************************************************************/
1864 void evel_open_throttle_spec()
1865 {
1866  EVEL_ENTER();
1867 
1868  /***************************************************************************/
1869  /* Check preconditions. */
1870  /***************************************************************************/
1871  assert(evel_throttle_spec_domain_value == NULL);
1872  assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
1873  assert(evel_temp_throttle == NULL);
1874 
1875  /***************************************************************************/
1876  /* Allocate and initialize an ::EVEL_THROTTLE_SPEC in which to hold */
1877  /* captured JSON elements. */
1878  /***************************************************************************/
1879  evel_temp_throttle = malloc(sizeof(EVEL_THROTTLE_SPEC));
1880  assert(evel_temp_throttle != NULL);
1881  dlist_initialize(&evel_temp_throttle->suppressed_field_names);
1882  dlist_initialize(&evel_temp_throttle->suppressed_nv_pairs_list);
1883  evel_temp_throttle->hash_field_names = NULL;
1884  evel_temp_throttle->hash_nv_pairs_list = NULL;
1885 
1886  EVEL_EXIT();
1887 }
1888 
1889 /**************************************************************************/
1892 void evel_close_throttle_spec()
1893 {
1894  EVEL_ENTER();
1895 
1896  /***************************************************************************/
1897  /* Decode, free and blank a captured event domain value. */
1898  /***************************************************************************/
1899  if (evel_throttle_spec_domain_value != NULL)
1900  {
1901  evel_throttle_spec_domain =
1902  evel_decode_domain(evel_throttle_spec_domain_value);
1903  free(evel_throttle_spec_domain_value);
1904  evel_throttle_spec_domain_value = NULL;
1905  }
1906 
1907  /***************************************************************************/
1908  /* Free off an empty working throttle spec, to stop it being used. This */
1909  /* state should be represented by a NULL pointer for the domain. */
1910  /***************************************************************************/
1911  if (evel_temp_throttle != NULL)
1912  {
1913  if (dlist_is_empty(&evel_temp_throttle->suppressed_field_names) &&
1914  dlist_is_empty(&evel_temp_throttle->suppressed_nv_pairs_list))
1915  {
1916  free(evel_temp_throttle);
1917  evel_temp_throttle = NULL;
1918  }
1919  }
1920 
1921  EVEL_EXIT();
1922 }
1923 
1924 /**************************************************************************/
1930 EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value)
1931 {
1932  EVEL_EVENT_DOMAINS result;
1933  int ii;
1934 
1935  EVEL_ENTER();
1936 
1937  /***************************************************************************/
1938  /* Check preconditions. */
1939  /***************************************************************************/
1940  assert(domain_value != NULL);
1941 
1942  result = EVEL_MAX_DOMAINS;
1943  for (ii = EVEL_DOMAIN_FAULT; ii < EVEL_MAX_DOMAINS; ii++)
1944  {
1945  assert(evel_domain_strings[ii] != NULL);
1946  if (strcmp(evel_domain_strings[ii], domain_value) == 0)
1947  {
1948  result = ii;
1949  }
1950  }
1951 
1952  EVEL_EXIT();
1953 
1954  return result;
1955 }
1956 
1957 /**************************************************************************/
1960 void evel_open_nv_pairs_list_entry()
1961 {
1962  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1963 
1964  EVEL_ENTER();
1965 
1966  /***************************************************************************/
1967  /* Check preconditions. */
1968  /***************************************************************************/
1969  assert(evel_temp_throttle != NULL);
1970 
1971  /***************************************************************************/
1972  /* Allocate and initialize an ::EVEL_SUPPRESSED_NV_PAIRS, and add it to */
1973  /* the list. */
1974  /***************************************************************************/
1975  nv_pairs = malloc(sizeof(EVEL_SUPPRESSED_NV_PAIRS));
1976  assert(nv_pairs != NULL);
1977  nv_pairs->nv_pair_field_name = NULL;
1979  nv_pairs->hash_nv_pair_names = NULL;
1980  dlist_push_last(&evel_temp_throttle->suppressed_nv_pairs_list, nv_pairs);
1981 
1982  EVEL_EXIT();
1983 }
1984 
1985 /**************************************************************************/
1988 void evel_close_nv_pairs_list_entry()
1989 {
1990  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
1991  EVEL_SUPPRESSED_NV_PAIRS * popped;
1992 
1993  EVEL_ENTER();
1994 
1995  /***************************************************************************/
1996  /* Get the latest nv pairs. This also performs the required checks. */
1997  /***************************************************************************/
1998  nv_pairs = evel_get_last_nv_pairs();
1999 
2000  /***************************************************************************/
2001  /* For a "suppressedNvPairsListEntry" to have any meaning, we need both */
2002  /* "nvPairFieldName" and "suppressedNvPairNames". If we don't, then pop */
2003  /* and free whatever we just collected. */
2004  /***************************************************************************/
2005  if ((nv_pairs->nv_pair_field_name == NULL) ||
2007  {
2008  popped = dlist_pop_last(&evel_temp_throttle->suppressed_nv_pairs_list);
2009  assert(popped == nv_pairs);
2010  evel_throttle_free_nv_pair(popped);
2011  }
2012 
2013  EVEL_EXIT();
2014 }
2015 
2016 /**************************************************************************/
2021 void evel_store_nv_pair_field_name(char * const value)
2022 {
2023  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2024 
2025  EVEL_ENTER();
2026 
2027  /***************************************************************************/
2028  /* Get the latest nv pairs. This also performs the required checks. */
2029  /***************************************************************************/
2030  nv_pairs = evel_get_last_nv_pairs();
2031 
2032  /***************************************************************************/
2033  /* Store the value. */
2034  /***************************************************************************/
2035  nv_pairs->nv_pair_field_name = value;
2036 
2037  EVEL_EXIT();
2038 }
2039 
2040 /**************************************************************************/
2045 void evel_store_nv_pair_name(char * const item)
2046 {
2047  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2048 
2049  EVEL_ENTER();
2050 
2051  /***************************************************************************/
2052  /* Get the latest nv pairs. This also performs the required checks. */
2053  /***************************************************************************/
2054  nv_pairs = evel_get_last_nv_pairs();
2055 
2056  /***************************************************************************/
2057  /* Store the item. */
2058  /***************************************************************************/
2059  dlist_push_last(&nv_pairs->suppressed_nv_pair_names, item);
2060 
2061  EVEL_EXIT();
2062 }
2063 
2064 /**************************************************************************/
2069 void evel_store_suppressed_field_name(char * const item)
2070 {
2071  EVEL_ENTER();
2072 
2073  /***************************************************************************/
2074  /* Check preconditions. */
2075  /***************************************************************************/
2076  assert(evel_temp_throttle != NULL);
2077 
2078  /***************************************************************************/
2079  /* Store the item. */
2080  /***************************************************************************/
2081  dlist_push_last(&evel_temp_throttle->suppressed_field_names, item);
2082 
2083  EVEL_EXIT();
2084 }
2085 
2086 /**************************************************************************/
2091 EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs()
2092 {
2094  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
2095 
2096  EVEL_ENTER();
2097 
2098  /***************************************************************************/
2099  /* Check preconditions. */
2100  /***************************************************************************/
2101  assert(evel_temp_throttle != NULL);
2102 
2103  /***************************************************************************/
2104  /* Get the pair that was added when we opened the list entry. */
2105  /***************************************************************************/
2106  dlist_item = dlist_get_last(&evel_temp_throttle->suppressed_nv_pairs_list);
2107  assert(dlist_item != NULL);
2108  nv_pairs = dlist_item->item;
2109  assert(nv_pairs != NULL);
2110 
2111  EVEL_EXIT();
2112 
2113  return nv_pairs;
2114 }
EVEL_EVENT_DOMAINS
Event domains for the various events we support.
Definition: evel.h:130
EVEL_JSON_STATE
The nature of the next token that we are iterating through.
Definition: evel_throttle.h:62
JSON token description.
Definition: jsmn.h:40
Another event.
Definition: evel.h:142
#define EVEL_DEBUG(FMT,...)
Definition: evel.h:3621
void evel_throttle_terminate()
Clean up event throttling.
EVEL_JSON_STATE json_state
Suppressed NV pairs list entry.
void evel_throttle_initialize()
Initialize event throttling to the default state.
DLIST_ITEM * dlist_get_first(DLIST *list)
Definition: double_list.c:162
An entry in the JSON stack.
void dlist_initialize(DLIST *list)
List initialization.
Definition: double_list.c:55
A chunk of memory used in the cURL functions.
Definition: evel_internal.h:77
void * item
Definition: double_list.h:47
bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC *throttle_spec, const char *const field_name)
Determine whether a field_name should be suppressed.
#define EVEL_DEBUG_ON()
Definition: evel.h:3644
int dlist_count(DLIST *list)
Definition: double_list.c:182
#define EVEL_EXIT()
Definition: evel.h:3631
DLIST suppressed_nv_pairs_list
#define EVEL_ENTER()
Definition: evel.h:3626
#define JSON_TOKEN_TYPES
jsmntype_t type
Definition: jsmn.h:41
EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain)
Return the EVEL_THROTTLE_SPEC for a given domain.
The JSON stack.
EVEL_JSON_STACK_ENTRY entry[EVEL_JSON_STACK_DEPTH]
Event Throttling Specification for a domain which is in a throttled state.
EVEL_JSON_COMMAND_STATE evel_json_command_state
#define EVEL_JSON_STACK_DEPTH
Definition: evel_throttle.h:50
#define EVEL_ERROR(FMT,...)
Definition: evel.h:3624
int start
Definition: jsmn.h:42
DLIST_ITEM * dlist_get_last(DLIST *list)
Definition: double_list.c:167
int json_count
int num_required
char * json_key
int end
Definition: jsmn.h:43
EVEL_JSON_COMMAND_STATE
States which we move through during JSON processing, tracking our way through the supported JSON stru...
Definition: evel_throttle.h:72
void * dlist_pop_last(DLIST *list)
Definition: double_list.c:73
void dlist_push_last(DLIST *list, void *item)
Definition: double_list.c:132
A Heartbeat event (event header only).
Definition: evel.h:133
int evel_get_measurement_interval()
Return the current measurement interval provided by the Event Listener.
struct hsearch_data * hash_nv_pairs_list
DLIST_ITEM * dlist_get_next(DLIST_ITEM *item)
Definition: double_list.c:172
bool evel_handle_command_list(const MEMORY_CHUNK *const chunk, const jsmntok_t *const json_tokens, const int num_tokens, MEMORY_CHUNK *const post)
Handle a JSON response from the listener, as a list of tokens from JSMN.
struct hsearch_data * hash_field_names
EVEL throttle definitions.
Double-linked list structure.
Definition: double_list.h:53
int size
Definition: jsmn.h:44
const MEMORY_CHUNK * chunk
#define EVEL_MAX_JSON_BODY
Definition: evel.h:101
bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC *throttle_spec, const char *const field_name, const char *const name)
Determine whether a name-value pair should be allowed (not suppressed).
#define EVEL_MAX_RESPONSE_TOKENS
Maximum number of tokens that we allow for in a JSON response.
Definition: evel_throttle.h:55
struct hsearch_data * hash_nv_pair_names
int dlist_is_empty(DLIST *list)
Definition: double_list.c:177