1 /*************************************************************************//**
3 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
5 * Unless otherwise specified, all software contained herein is
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
17 ****************************************************************************/
19 /**************************************************************************//**
23 * Simple event manager that is responsible for taking events (Heartbeats,
24 * Faults and Measurements) from the ring-buffer and posting them to the API.
26 ****************************************************************************/
33 #include <curl/curl.h>
36 #include "evel_internal.h"
37 #include "ring_buffer.h"
38 #include "evel_throttle.h"
40 /**************************************************************************//**
41 * How long we're prepared to wait for the API service to respond in
43 *****************************************************************************/
44 static const int EVEL_API_TIMEOUT = 5;
46 /**************************************************************************//**
47 * Wait time if both the collectors are not responding
48 *****************************************************************************/
49 static const int EVEL_COLLECTOR_RECONNECTION_WAIT_TIME = 120;
51 /*****************************************************************************/
52 /* Prototypes of locally scoped functions. */
53 /*****************************************************************************/
54 static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp);
55 static void * event_handler(void *arg);
56 static bool evel_handle_response_tokens(const MEMORY_CHUNK * const chunk,
57 const jsmntok_t * const json_tokens,
59 MEMORY_CHUNK * const post);
60 static bool evel_tokens_match_command_list(const MEMORY_CHUNK * const chunk,
61 const jsmntok_t * const json_token,
62 const int num_tokens);
63 static bool evel_token_equals_string(const MEMORY_CHUNK * const chunk,
64 const jsmntok_t * const json_token,
65 const char * check_string);
66 static EVEL_ERR_CODES evel_setup_curl();
67 static EVEL_ERR_CODES evel_send_to_another_collector(const EVEL_EVENT_DOMAINS evel_domain, char * json_body, size_t json_size);
69 /**************************************************************************//**
70 * Buffers for error strings from libcurl.
71 *****************************************************************************/
72 static char curl_err_string[CURL_ERROR_SIZE] = "<NULL>";
74 /**************************************************************************//**
75 * Handle for the API into libcurl.
76 *****************************************************************************/
77 static CURL * curl_handle = NULL;
78 int curr_global_handles = 0;
80 /**************************************************************************//**
81 * Special headers that we send.
82 *****************************************************************************/
83 static struct curl_slist * hdr_chunk = NULL;
85 /**************************************************************************//**
86 * Message queue for sending events to the API.
87 *****************************************************************************/
88 static ring_buffer event_buffer;
90 /**************************************************************************//**
91 * Single pending priority post, which can be generated as a result of a
92 * response to an event. Currently only used to respond to a commandList.
93 *****************************************************************************/
94 static MEMORY_CHUNK priority_post;
96 /**************************************************************************//**
97 * The thread which is responsible for handling events off of the ring-buffer
98 * and posting them to the Event Handler API.
99 *****************************************************************************/
100 static pthread_t evt_handler_thread;
102 /**************************************************************************//**
103 * Variable to convey to the event handler thread what the foreground wants it
105 *****************************************************************************/
106 static EVT_HANDLER_STATE evt_handler_state = EVT_HANDLER_UNINITIALIZED;
108 /**************************************************************************//**
109 * The configured API URL for event and throttling.
110 *****************************************************************************/
111 static char * evel_event_api_url;
112 static char * evel_throt_api_url;
113 static char * evel_batch_api_url;
115 static char * evel_bevent_api_url;
116 static char * evel_bthrot_api_url;
117 static char * evel_bbatch_api_url;
119 /**************************************************************************//**
120 * Storage for other CURL related parameters
121 *****************************************************************************/
122 int evel_secure = -1;
123 int evel_verbosity = -1;
125 long evel_verify_peer = 0;
126 long evel_verify_host = 0;
128 static char * evel_source_ip = NULL;
129 static char * evel_source_ip_bakup = NULL;
130 static char * evel_cert_file_path = NULL;
131 static char * evel_key_file_path = NULL;
132 static char * evel_ca_info = NULL;
133 static char * evel_ca_file_path = NULL;
134 static char * evel_username = NULL;
135 static char * evel_password = NULL;
136 static char * evel_username2 = NULL;
137 static char * evel_password2 = NULL;
139 static long http_response_code = 0;
140 static int evel_collector_id = 1;
141 /**************************************************************************//**
142 * Initialize the event handler.
144 * Primarily responsible for getting CURL ready for use.
146 * @param[in] event_api_url
147 * The URL where the Vendor Event Listener API is expected
149 * @param[in] throt_api_url
150 * The URL where the Throttling API is expected to be.
151 * @param[in] source_ip Source IP of VES Agent
152 * @param[in] ring_buf_size Initial size of ring buffer
153 * @param[in] secure Whether Using http or https
154 * @param[in] cert_file_path Path to Client Certificate file
155 * @param[in] key_file_path Path to Client key file
156 * @param[in] ca_info Path to CA info file
157 * @param[in] ca_file_path Path to CA file
158 * @param[in] verify_peer Using peer verification or not 0 or 1
159 * @param[in] verify_host Using host verification or not 0 or 1
160 * @param[in] username The username for the Basic Authentication of requests.
161 * @param[in] password The password for the Basic Authentication of requests.
162 * @param verbosity 0 for normal operation, positive values for chattier
164 *****************************************************************************/
165 EVEL_ERR_CODES event_handler_initialize(const char * const event_api_url,
166 const char * const bakup_api_url,
167 const char * const throt_api_url,
168 const char * const source_ip,
169 const char * const source_ip_bakup,
172 const char * const cert_file_path,
173 const char * const key_file_path,
174 const char * const ca_info,
175 const char * const ca_file_path,
178 const char * const username,
179 const char * const password,
180 const char * const username2,
181 const char * const password2,
184 int rc = EVEL_SUCCESS;
185 char batch_api_url[EVEL_MAX_URL_LEN + 1] = {0};
189 /***************************************************************************/
190 /* Check assumptions. */
191 /***************************************************************************/
192 assert(event_api_url != NULL);
193 assert(throt_api_url != NULL);
194 assert(username != NULL);
195 assert(password != NULL);
196 if( bakup_api_url != NULL )
198 assert(username2 != NULL);
199 assert(password2 != NULL);
202 /***************************************************************************/
203 /* Store the API URLs. */
204 /***************************************************************************/
205 evel_event_api_url = strdup(event_api_url);
206 assert(evel_event_api_url != NULL);
207 sprintf(batch_api_url,"%s/eventBatch",event_api_url);
208 evel_batch_api_url = strdup(batch_api_url);
209 assert(evel_batch_api_url != NULL);
210 evel_throt_api_url = strdup(throt_api_url);
211 assert(evel_throt_api_url != NULL);
213 curr_global_handles = 1;
215 if( bakup_api_url != NULL )
217 evel_bevent_api_url = strdup(bakup_api_url);
218 assert(evel_bevent_api_url != NULL);
219 sprintf(batch_api_url,"%s/eventBatch",bakup_api_url);
220 evel_bbatch_api_url = strdup(batch_api_url);
221 assert(evel_bbatch_api_url != NULL);
222 evel_bthrot_api_url = strdup(throt_api_url);
223 assert(evel_bthrot_api_url != NULL);
224 curr_global_handles = 2;
227 /***************************************************************************/
228 /* Store other parameters */
229 /***************************************************************************/
230 evel_secure = secure;
231 evel_verbosity = verbosity;
233 evel_verify_peer = verify_peer;
234 evel_verify_host = verify_host;
236 evel_source_ip = NULL;
237 if (source_ip != NULL)
239 evel_source_ip = strdup(source_ip);
240 assert(evel_source_ip != NULL);
243 evel_source_ip_bakup = NULL;
244 if (source_ip_bakup != NULL)
246 evel_source_ip_bakup = strdup(source_ip_bakup);
247 assert(evel_source_ip_bakup != NULL);
250 evel_cert_file_path = NULL;
251 if (cert_file_path != NULL)
253 evel_cert_file_path = strdup(cert_file_path);
254 assert(evel_cert_file_path != NULL);
257 evel_key_file_path = NULL;
258 if (key_file_path != NULL)
260 evel_key_file_path = strdup(key_file_path);
261 assert(evel_key_file_path != NULL);
267 evel_ca_info = strdup(ca_info);
268 assert(evel_ca_info != NULL);
271 evel_ca_file_path = NULL;
272 if (ca_file_path != NULL)
274 evel_ca_file_path = strdup(ca_file_path);
275 assert(evel_ca_file_path != NULL);
278 evel_username = NULL;
279 if (username != NULL)
281 evel_username = strdup(username);
282 assert(evel_username != NULL);
285 evel_password = NULL;
286 if (password != NULL)
288 evel_password = strdup(password);
289 assert(evel_password != NULL);
292 evel_username2 = NULL;
293 if (username2 != NULL)
295 evel_username2 = strdup(username2);
296 assert(evel_username2 != NULL);
299 evel_password2 = NULL;
300 if (password2 != NULL)
302 evel_password2 = strdup(password2);
303 assert(evel_password2 != NULL);
306 curl_version_info_data *d = curl_version_info(CURLVERSION_NOW);
307 /* compare with the 24 bit hex number in 8 bit fields */
308 if(d->version_num >= 0x072100) {
309 /* this is libcurl 7.33.0 or later */
310 EVEL_INFO("7.33 or later Curl version %x.",d->version_num);
313 EVEL_INFO("Old Curl version.");
316 /***************************************************************************/
317 /* Initialize a message ring-buffer to be used between the foreground and */
318 /* the thread which sends the messages. This can't fail. */
319 /***************************************************************************/
320 if( ring_buf_size < EVEL_EVENT_BUFFER_DEPTH )
322 log_error_state("Warning: Failed to initialize Ring buffer size to %d. ",
326 ring_buffer_initialize(&event_buffer, EVEL_EVENT_BUFFER_DEPTH);
335 /**************************************************************************//**
336 * Setup the curl connection to collector
338 * Primarily responsible for getting CURL ready to send message. Also it would
339 * be used to swithch over to other collector
340 *****************************************************************************/
341 static EVEL_ERR_CODES evel_setup_curl()
343 int rc = EVEL_SUCCESS;
344 CURLcode curl_rc = CURLE_OK;
345 char local_address[64];
346 char * api_url = NULL;
347 char * username = NULL;
348 char * password = NULL;
349 char * source_ip = NULL;
353 if (evel_collector_id > 2)
355 rc = EVEL_CURL_LIBRARY_FAIL;
356 log_error_state("Wrong evel_collector- value > 2");
360 /***************************************************************************/
361 /* Initialize the local variable with proper global variables that are */
362 /* required to setup the connection */
363 /***************************************************************************/
364 if (evel_collector_id == 1)
366 api_url = evel_event_api_url;
367 source_ip = evel_source_ip;
368 username = evel_username;
369 password = evel_password;
371 else if (evel_collector_id == 2)
373 api_url = evel_bevent_api_url;
374 source_ip = evel_source_ip_bakup;
375 username = evel_username2;
376 password = evel_password2;
378 /***************************************************************************/
379 /* Clean-up the cURL library. */
380 /***************************************************************************/
381 if (curl_handle != NULL)
383 curl_easy_cleanup(curl_handle);
386 if (hdr_chunk != NULL)
388 curl_slist_free_all(hdr_chunk);
392 /***************************************************************************/
393 /* Start the CURL library. Note that this initialization is not threadsafe */
394 /* which imposes a constraint that the EVEL library is initialized before */
395 /* any threads are started. */
396 /***************************************************************************/
397 curl_rc = curl_global_init(CURL_GLOBAL_SSL);
398 if (curl_rc != CURLE_OK)
400 rc = EVEL_CURL_LIBRARY_FAIL;
401 log_error_state("Failed to initialize libCURL. Error code=%d", curl_rc);
405 /***************************************************************************/
406 /* Get a curl handle which we'll use for all of our output. */
407 /***************************************************************************/
408 curl_handle = curl_easy_init();
409 if (curl_handle == NULL)
411 rc = EVEL_CURL_LIBRARY_FAIL;
412 log_error_state("Failed to get libCURL handle");
416 /***************************************************************************/
417 /* Prime the library to give friendly error codes. */
418 /***************************************************************************/
419 curl_rc = curl_easy_setopt(curl_handle,
422 if (curl_rc != CURLE_OK)
424 rc = EVEL_CURL_LIBRARY_FAIL;
425 log_error_state("Failed to initialize libCURL to provide friendly errors. "
426 "Error code=%d", curl_rc);
430 /***************************************************************************/
431 /* If running in verbose mode generate more output. */
432 /***************************************************************************/
433 if (evel_verbosity > 0)
435 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
436 if (curl_rc != CURLE_OK)
438 rc = EVEL_CURL_LIBRARY_FAIL;
439 log_error_state("Failed to initialize libCURL to be verbose. "
440 "Error code=%d", curl_rc);
445 /***************************************************************************/
446 /* Set the URL for the API. */
447 /***************************************************************************/
448 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, api_url);
449 if (curl_rc != CURLE_OK)
451 rc = EVEL_CURL_LIBRARY_FAIL;
452 log_error_state("Failed to initialize libCURL with the API URL. "
453 "Error code=%d (%s)", curl_rc, curl_err_string);
456 EVEL_INFO("Initializing CURL to send events to: %s", api_url);
458 /***************************************************************************/
459 /* send all data to this function. */
460 /***************************************************************************/
461 curl_rc = curl_easy_setopt(curl_handle,
462 CURLOPT_WRITEFUNCTION,
463 evel_write_callback);
464 if (curl_rc != CURLE_OK)
466 rc = EVEL_CURL_LIBRARY_FAIL;
467 log_error_state("Failed to initialize libCURL with the write callback. "
468 "Error code=%d (%s)", curl_rc, curl_err_string);
472 /***************************************************************************/
473 /* configure local ip address if provided */
474 /* Default ip if NULL */
475 /***************************************************************************/
476 if( source_ip != NULL )
478 snprintf(local_address,sizeof(local_address),source_ip);
479 if( local_address[0] != '\0' )
481 curl_rc = curl_easy_setopt(curl_handle,
484 if (curl_rc != CURLE_OK)
486 rc = EVEL_CURL_LIBRARY_FAIL;
487 log_error_state("Failed to initialize libCURL with the local address. "
488 "Error code=%d (%s)", curl_rc, curl_err_string);
494 /***************************************************************************/
495 /* configure SSL options for HTTPS transfers */
496 /***************************************************************************/
499 if( evel_cert_file_path != NULL )
501 curl_rc = curl_easy_setopt(curl_handle,
503 evel_cert_file_path);
504 if (curl_rc != CURLE_OK)
506 rc = EVEL_CURL_LIBRARY_FAIL;
507 log_error_state("Failed to initialize libCURL with the client cert. "
508 "Error code=%d (%s)", curl_rc, curl_err_string);
513 if( evel_key_file_path != NULL )
515 curl_rc = curl_easy_setopt(curl_handle,
518 if (curl_rc != CURLE_OK)
520 rc = EVEL_CURL_LIBRARY_FAIL;
521 log_error_state("Failed to initialize libCURL with the client key. "
522 "Error code=%d (%s)", curl_rc, curl_err_string);
527 if( evel_ca_info != NULL )
529 curl_rc = curl_easy_setopt(curl_handle,
532 if (curl_rc != CURLE_OK)
534 rc = EVEL_CURL_LIBRARY_FAIL;
535 log_error_state("Failed to initialize libCURL with the CA cert file. "
536 "Error code=%d (%s)", curl_rc, curl_err_string);
541 if( evel_ca_file_path != NULL )
543 curl_rc = curl_easy_setopt(curl_handle,
546 if (curl_rc != CURLE_OK)
548 rc = EVEL_CURL_LIBRARY_FAIL;
549 log_error_state("Failed to initialize libCURL with the CA cert path. "
550 "Error code=%d (%s)", curl_rc, curl_err_string);
555 curl_rc = curl_easy_setopt(curl_handle,
556 CURLOPT_SSL_VERIFYPEER,
558 if (curl_rc != CURLE_OK)
560 rc = EVEL_CURL_LIBRARY_FAIL;
561 log_error_state("Failed to initialize libCURL with SSL Server verification. "
562 "Error code=%d (%s)", curl_rc, curl_err_string);
565 curl_rc = curl_easy_setopt(curl_handle,
566 CURLOPT_SSL_VERIFYHOST,
568 if (curl_rc != CURLE_OK)
570 rc = EVEL_CURL_LIBRARY_FAIL;
571 log_error_state("Failed to initialize libCURL with Client host verification. "
572 "Error code=%d (%s)", curl_rc, curl_err_string);
580 /***************************************************************************/
581 /* some servers don't like requests that are made without a user-agent */
582 /* field, so we provide one. */
583 /***************************************************************************/
584 curl_rc = curl_easy_setopt(curl_handle,
586 "libcurl-agent/1.0");
587 if (curl_rc != CURLE_OK)
589 rc = EVEL_CURL_LIBRARY_FAIL;
590 log_error_state("Failed to initialize libCURL to upload. "
591 "Error code=%d (%s)", curl_rc, curl_err_string);
595 /***************************************************************************/
596 /* Specify that we are going to POST data. */
597 /***************************************************************************/
598 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
599 if (curl_rc != CURLE_OK)
601 rc = EVEL_CURL_LIBRARY_FAIL;
602 log_error_state("Failed to initialize libCURL to upload. "
603 "Error code=%d (%s)", curl_rc, curl_err_string);
607 /***************************************************************************/
608 /* we want to use our own read function. */
609 /***************************************************************************/
610 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION, read_callback);
611 if (curl_rc != CURLE_OK)
613 rc = EVEL_CURL_LIBRARY_FAIL;
614 log_error_state("Failed to initialize libCURL to upload using read "
615 "function. Error code=%d (%s)", curl_rc, curl_err_string);
619 /***************************************************************************/
620 /* All of our events are JSON encoded. We also suppress the */
621 /* Expect: 100-continue header that we would otherwise get since it */
622 /* confuses some servers. */
624 /* @TODO: do AT&T want this behavior? */
625 /***************************************************************************/
626 hdr_chunk = curl_slist_append(hdr_chunk, "Content-type: application/json");
627 hdr_chunk = curl_slist_append(hdr_chunk, "Expect:");
629 /***************************************************************************/
630 /* set our custom set of headers. */
631 /***************************************************************************/
632 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, hdr_chunk);
633 if (curl_rc != CURLE_OK)
635 rc = EVEL_CURL_LIBRARY_FAIL;
636 log_error_state("Failed to initialize libCURL to use custom headers. "
637 "Error code=%d (%s)", curl_rc, curl_err_string);
641 /***************************************************************************/
642 /* Set the timeout for the operation. */
643 /***************************************************************************/
644 curl_rc = curl_easy_setopt(curl_handle,
647 if (curl_rc != CURLE_OK)
649 rc = EVEL_CURL_LIBRARY_FAIL;
650 log_error_state("Failed to initialize libCURL for API timeout. "
651 "Error code=%d (%s)", curl_rc, curl_err_string);
655 /***************************************************************************/
656 /* Set that we want Basic authentication with username:password Base-64 */
657 /* encoded for the operation. */
658 /***************************************************************************/
659 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
660 if (curl_rc != CURLE_OK)
662 rc = EVEL_CURL_LIBRARY_FAIL;
663 log_error_state("Failed to initialize libCURL for Basic Authentication. "
664 "Error code=%d (%s)", curl_rc, curl_err_string);
667 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_USERNAME, username);
668 if (curl_rc != CURLE_OK)
670 rc = EVEL_CURL_LIBRARY_FAIL;
671 log_error_state("Failed to initialize libCURL with username. "
672 "Error code=%d (%s)", curl_rc, curl_err_string);
675 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_PASSWORD, password);
676 if (curl_rc != CURLE_OK)
678 rc = EVEL_CURL_LIBRARY_FAIL;
679 log_error_state("Failed to initialize libCURL with password. "
680 "Error code=%d (%s)", curl_rc, curl_err_string);
684 /***************************************************************************/
685 /* Initialize the priority post buffer to empty. */
686 /***************************************************************************/
687 priority_post.memory = NULL;
695 /**************************************************************************//**
696 * Run the event handler.
698 * Spawns the thread responsible for handling events and sending them to the
701 * @return Status code.
702 * @retval ::EVEL_SUCCESS if everything OK.
703 * @retval One of ::EVEL_ERR_CODES if there was a problem.
704 *****************************************************************************/
705 EVEL_ERR_CODES event_handler_run()
707 EVEL_ERR_CODES rc = EVEL_SUCCESS;
712 /***************************************************************************/
713 /* Start the event handler thread. */
714 /***************************************************************************/
715 evt_handler_state = EVT_HANDLER_INACTIVE;
716 pthread_rc = pthread_create(&evt_handler_thread, NULL, event_handler, NULL);
719 rc = EVEL_PTHREAD_LIBRARY_FAIL;
720 log_error_state("Failed to start event handler thread. "
721 "Error code=%d", pthread_rc);
728 /**************************************************************************//**
729 * Terminate the event handler.
731 * Shuts down the event handler thread in as clean a way as possible. Sets the
732 * global exit flag and then signals the thread to interrupt it since it's
733 * most likely waiting on the ring-buffer.
735 * Having achieved an orderly shutdown of the event handler thread, clean up
736 * the cURL library's resources cleanly.
738 * @return Status code.
739 * @retval ::EVEL_SUCCESS if everything OK.
740 * @retval One of ::EVEL_ERR_CODES if there was a problem.
741 *****************************************************************************/
742 EVEL_ERR_CODES event_handler_terminate()
744 EVEL_ERR_CODES rc = EVEL_SUCCESS;
747 EVENT_INTERNAL *event = NULL;
749 /***************************************************************************/
750 /* Make sure that we were initialized before trying to terminate the */
751 /* event handler thread. */
752 /***************************************************************************/
753 if (evt_handler_state != EVT_HANDLER_UNINITIALIZED)
755 /*************************************************************************/
756 /* Make sure that the event handler knows it's time to die. */
757 /*************************************************************************/
758 event = evel_new_internal_event(EVT_CMD_TERMINATE,"EVELinternal","EVELid");
761 /***********************************************************************/
762 /* We failed to get an event, but we don't bail out - we will just */
763 /* clean up what we can and continue on our way, since we're exiting */
765 /***********************************************************************/
766 EVEL_ERROR("Failed to get internal event - perform dirty exit instead!");
770 /***********************************************************************/
771 /* Post the event then wait for the Event Handler to exit. Set the */
772 /* global command, too, in case the ring-buffer is full. */
773 /***********************************************************************/
774 EVEL_DEBUG("Sending event to Event Hander to request it to exit.");
775 evt_handler_state = EVT_HANDLER_REQUEST_TERMINATE;
776 evel_post_event((EVENT_HEADER *) event);
777 pthread_join(evt_handler_thread, NULL);
778 EVEL_DEBUG("Event Handler thread has exited.");
783 EVEL_DEBUG("Event handler was not initialized, so no need to kill it");
786 /***************************************************************************/
787 /* Clean-up the cURL library. */
788 /***************************************************************************/
789 if (curl_handle != NULL)
791 curl_easy_cleanup(curl_handle);
794 if (hdr_chunk != NULL)
796 curl_slist_free_all(hdr_chunk);
800 /***************************************************************************/
801 /* Free off the stored API URL strings. */
802 /***************************************************************************/
803 if (evel_event_api_url != NULL)
805 free(evel_event_api_url);
806 evel_event_api_url = NULL;
808 if (evel_batch_api_url != NULL)
810 free(evel_batch_api_url);
811 evel_batch_api_url = NULL;
813 if (evel_throt_api_url != NULL)
815 free(evel_throt_api_url);
816 evel_throt_api_url = NULL;
823 /**************************************************************************//**
826 * @note So far as the caller is concerned, successfully posting the event
827 * relinquishes all responsibility for the event - the library will take care
828 * of freeing the event in due course.
830 * @param event The event to be posted.
832 * @returns Status code
833 * @retval EVEL_SUCCESS On success
834 * @retval "One of ::EVEL_ERR_CODES" On failure.
835 *****************************************************************************/
836 EVEL_ERR_CODES evel_post_event(EVENT_HEADER * event)
838 int rc = EVEL_SUCCESS;
842 /***************************************************************************/
843 /* Check preconditions. */
844 /***************************************************************************/
845 assert(event != NULL);
847 /***************************************************************************/
848 /* We need to make sure that we are either initializing or running */
849 /* normally before writing the event into the buffer so that we can */
850 /* guarantee that the ring-buffer empties properly on exit. */
851 /***************************************************************************/
852 if ((evt_handler_state == EVT_HANDLER_ACTIVE) ||
853 (evt_handler_state == EVT_HANDLER_INACTIVE) ||
854 (evt_handler_state == EVT_HANDLER_REQUEST_TERMINATE))
856 if (ring_buffer_write(&event_buffer, event) == 0)
858 log_error_state("Failed to write event to buffer - event dropped!");
859 rc = EVEL_EVENT_BUFFER_FULL;
860 evel_free_event(event);
865 /*************************************************************************/
866 /* System is not in active operation, so reject the event. */
867 /*************************************************************************/
868 log_error_state("Event Handler system not active - event dropped!");
869 rc = EVEL_EVENT_HANDLER_INACTIVE;
870 evel_free_event(event);
877 /**************************************************************************//**
878 * Post an event to the Vendor Event Listener API.
880 * @returns Status code
881 * @retval EVEL_SUCCESS On success
882 * @retval "One of ::EVEL_ERR_CODES" On failure.
883 *****************************************************************************/
884 static EVEL_ERR_CODES evel_post_api(char * msg, size_t size)
886 int rc = EVEL_SUCCESS;
887 CURLcode curl_rc = CURLE_OK;
888 MEMORY_CHUNK rx_chunk;
889 MEMORY_CHUNK tx_chunk;
893 /***************************************************************************/
894 /* Create the memory chunk to be used for the response to the post. The */
895 /* will be realloced. */
896 /***************************************************************************/
897 rx_chunk.memory = malloc(1);
898 assert(rx_chunk.memory != NULL);
901 /***************************************************************************/
902 /* Create the memory chunk to be sent as the body of the post. */
903 /***************************************************************************/
904 tx_chunk.memory = msg;
905 tx_chunk.size = size;
906 EVEL_DEBUG("Sending chunk of size %d", tx_chunk.size);
908 /***************************************************************************/
909 /* Point to the data to be received. */
910 /***************************************************************************/
911 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &rx_chunk);
912 if (curl_rc != CURLE_OK)
914 rc = EVEL_CURL_LIBRARY_FAIL;
915 log_error_state("Failed to initialize libCURL to upload. "
916 "Error code=%d (%s)", curl_rc, curl_err_string);
919 EVEL_DEBUG("Initialized data to receive");
921 /***************************************************************************/
922 /* Pointer to pass to our read function */
923 /***************************************************************************/
924 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_READDATA, &tx_chunk);
925 if (curl_rc != CURLE_OK)
927 rc = EVEL_CURL_LIBRARY_FAIL;
928 log_error_state("Failed to set upload data for libCURL to upload. "
929 "Error code=%d (%s)", curl_rc, curl_err_string);
932 EVEL_DEBUG("Initialized data to send");
934 /***************************************************************************/
935 /* Size of the data to transmit. */
936 /***************************************************************************/
937 curl_rc = curl_easy_setopt(curl_handle,
938 CURLOPT_POSTFIELDSIZE,
940 if (curl_rc != CURLE_OK)
942 rc = EVEL_CURL_LIBRARY_FAIL;
943 log_error_state("Failed to set length of upload data for libCURL to "
944 "upload. Error code=%d (%s)", curl_rc, curl_err_string);
947 EVEL_DEBUG("Initialized length of data to send");
949 /***************************************************************************/
950 /* Now run off and do what you've been told! */
951 /***************************************************************************/
952 http_response_code = 0;
954 curl_rc = curl_easy_perform(curl_handle);
955 if (curl_rc != CURLE_OK)
957 rc = EVEL_CURL_LIBRARY_FAIL;
958 log_error_state("Failed to transfer an event to Vendor Event Listener! "
959 "Error code=%d (%s)", curl_rc, curl_err_string);
960 EVEL_ERROR("Dropped event: %s", msg);
964 /***************************************************************************/
965 /* See what response we got - any 2XX response is good. */
966 /***************************************************************************/
967 curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_response_code);
968 EVEL_DEBUG("HTTP response code: %d", http_response_code);
969 if ((http_response_code / 100) == 2)
971 /*************************************************************************/
972 /* If the server responded with data it may be interesting but not a */
974 /*************************************************************************/
975 if ((rx_chunk.size > 0) && (rx_chunk.memory != NULL))
977 EVEL_DEBUG("Server returned data = %d (%s)",
981 /***********************************************************************/
982 /* If this is a response to priority post, then we're not interested. */
983 /***********************************************************************/
984 if (priority_post.memory != NULL)
986 EVEL_ERROR("Ignoring priority post response");
990 evel_handle_event_response(&rx_chunk, &priority_post);
996 EVEL_ERROR("Unexpected HTTP response code: %d with data size %d (%s)",
999 rx_chunk.size > 0 ? rx_chunk.memory : "NONE");
1000 EVEL_ERROR("Potentially dropped event: %s", msg);
1004 free(rx_chunk.memory);
1009 /**************************************************************************//**
1010 * Send event to another collector
1012 * Identify the next collector and try sending the event to that collector
1013 ****************************************************************************/
1014 static EVEL_ERR_CODES evel_send_to_another_collector(
1015 const EVEL_EVENT_DOMAINS evel_domain,
1019 int rc = EVEL_SUCCESS;
1024 if ((evel_collector_id == 1) && (curr_global_handles == 2))
1026 evel_collector_id =2;
1028 else if (evel_collector_id == 2)
1030 evel_collector_id =1;
1033 rc = evel_setup_curl();
1035 if ( rc == EVEL_SUCCESS)
1037 if (evel_collector_id == 1)
1039 if (evel_domain == EVEL_DOMAIN_BATCH)
1040 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_batch_api_url);
1042 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_event_api_url);
1044 else if (evel_collector_id == 2)
1046 if (evel_domain == EVEL_DOMAIN_BATCH)
1047 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_bbatch_api_url);
1049 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_bevent_api_url);
1052 rc = evel_post_api(json_body, json_size);
1060 /**************************************************************************//**
1061 * Callback function to provide data to send.
1063 * Copy data into the supplied buffer, read_callback::ptr, checking size
1066 * @returns Number of bytes placed into read_callback::ptr. 0 for EOF.
1067 *****************************************************************************/
1068 static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
1071 size_t bytes_to_write = 0;
1072 MEMORY_CHUNK *tx_chunk = (MEMORY_CHUNK *)userp;
1076 bytes_to_write = min(size*nmemb, tx_chunk->size);
1078 if (bytes_to_write > 0)
1080 EVEL_DEBUG("Going to try to write %d bytes", bytes_to_write);
1081 strncpy((char *)ptr, tx_chunk->memory, bytes_to_write);
1082 tx_chunk->memory += bytes_to_write;
1083 tx_chunk->size -= bytes_to_write;
1084 rtn = bytes_to_write;
1088 EVEL_DEBUG("Reached EOF");
1095 /**************************************************************************//**
1096 * Callback function to provide returned data.
1098 * Copy data into the supplied buffer, write_callback::ptr, checking size
1101 * @returns Number of bytes placed into write_callback::ptr. 0 for EOF.
1102 *****************************************************************************/
1103 size_t evel_write_callback(void *contents,
1108 size_t realsize = size * nmemb;
1109 MEMORY_CHUNK * rx_chunk = (MEMORY_CHUNK *)userp;
1113 EVEL_DEBUG("Called with %d chunks of %d size = %d", nmemb, size, realsize);
1114 EVEL_DEBUG("rx chunk size is %d", rx_chunk->size);
1116 rx_chunk->memory = realloc(rx_chunk->memory, rx_chunk->size + realsize + 1);
1117 if(rx_chunk->memory == NULL) {
1118 /* out of memory! */
1119 printf("not enough memory (realloc returned NULL)\n");
1123 memcpy(&(rx_chunk->memory[rx_chunk->size]), contents, realsize);
1124 rx_chunk->size += realsize;
1125 rx_chunk->memory[rx_chunk->size] = 0;
1127 EVEL_DEBUG("Rx data: %s", rx_chunk->memory);
1128 EVEL_DEBUG("Returning: %d", realsize);
1134 /**************************************************************************//**
1137 * Watch for messages coming on the internal queue and send them to the
1140 * param[in] arg Argument - unused.
1141 *****************************************************************************/
1142 static void * event_handler(void * arg __attribute__ ((unused)))
1145 EVENT_HEADER * msg = NULL;
1146 EVENT_INTERNAL * internal_msg = NULL;
1148 char json_body[EVEL_MAX_JSON_BODY];
1149 int rc = EVEL_SUCCESS;
1151 int collector_down_count = 0;
1152 int switch_coll = 0;
1154 EVEL_INFO("Event handler thread started");
1156 /***************************************************************************/
1157 /* Set this thread to be cancellable immediately. */
1158 /***************************************************************************/
1159 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type);
1161 /***************************************************************************/
1162 /* Set the handler as active, defending against weird situations like */
1163 /* immediately shutting down after initializing the library so the */
1164 /* handler never gets started up properly. */
1165 /***************************************************************************/
1166 if (evt_handler_state == EVT_HANDLER_INACTIVE)
1168 evt_handler_state = EVT_HANDLER_ACTIVE;
1172 EVEL_ERROR("Event Handler State was not INACTIVE at start-up - "
1173 "Handler will exit immediately!");
1175 /***************************************************************************/
1176 /* Set the connection to collector */
1177 /***************************************************************************/
1180 evel_collector_id = 1;
1181 rc = evel_setup_curl();
1183 if ( rc != EVEL_SUCCESS)
1185 EVEL_ERROR("Failed to setup the first collector. Error code=%d", rc);
1186 if (curr_global_handles == 2)
1188 EVEL_DEBUG("Switching to other collector");
1190 evel_collector_id = 2;
1192 rc = evel_setup_curl();
1193 if ( rc != EVEL_SUCCESS)
1195 EVEL_ERROR("Failed to setup the connection to second collector also, Error code%d", rc);
1196 sleep(EVEL_COLLECTOR_RECONNECTION_WAIT_TIME);
1197 collector_down_count = collector_down_count + 1;
1198 EVEL_ERROR("Collectors setup issue- retry count=%d", collector_down_count);
1202 collector_down_count = 0;
1208 sleep(EVEL_COLLECTOR_RECONNECTION_WAIT_TIME);
1209 collector_down_count = collector_down_count + 1;
1210 EVEL_ERROR("Collector setup issue-retry count=%d", collector_down_count);
1215 collector_down_count = 0;
1220 while (evt_handler_state == EVT_HANDLER_ACTIVE)
1222 /*************************************************************************/
1223 /* Wait for a message to be received. */
1224 /*************************************************************************/
1225 EVEL_DEBUG("Event handler getting any messages");
1226 msg = ring_buffer_read(&event_buffer);
1228 /*************************************************************************/
1229 /* Internal events get special treatment while regular events get posted */
1230 /* to the far side. */
1231 /*************************************************************************/
1232 if (msg->event_domain == EVEL_DOMAIN_BATCH )
1234 EVEL_DEBUG("Batch event received");
1236 /***********************************************************************/
1237 /* Encode the event in JSON. */
1238 /***********************************************************************/
1239 json_size = evel_json_encode_batch_event(json_body, EVEL_MAX_JSON_BODY, msg);
1241 /***************************************************************************/
1242 /* Set the URL for the API. */
1243 /***************************************************************************/
1244 if (evel_collector_id == 1)
1246 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_batch_api_url);
1250 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_bbatch_api_url);
1253 if (curl_rc != CURLE_OK)
1255 rc = EVEL_CURL_LIBRARY_FAIL;
1256 log_error_state("Failed to initialize libCURL with the Batch API URL. "
1257 "Error code=%d (%s)", curl_rc, curl_err_string);
1260 /***********************************************************************/
1261 /* Send the JSON across the API. */
1262 /***********************************************************************/
1263 EVEL_DEBUG("Sending Batch JSON of size %d is: %s", json_size, json_body);
1264 rc = evel_post_api(json_body, json_size);
1267 if ((rc == EVEL_SUCCESS) && ((http_response_code / 100) != 2))
1270 if (http_response_code == 400) // 400 - Bad JSON related return code
1274 if ((rc != EVEL_SUCCESS) || (switch_coll == 1))
1276 EVEL_ERROR("Failed to transfer the data. Error code=%d", rc);
1277 EVEL_DEBUG("Switching to other collector if any");
1281 if (curr_global_handles == 2)
1283 rc = evel_send_to_another_collector(msg->event_domain, json_body, json_size);
1286 if ((rc == EVEL_SUCCESS) && ((http_response_code / 100) != 2))
1289 if (http_response_code == 400) // 400 - Bad JSON related return code
1292 if ((rc != EVEL_SUCCESS) || (switch_coll == 1))
1294 sleep(EVEL_COLLECTOR_RECONNECTION_WAIT_TIME);
1295 collector_down_count = collector_down_count + 1;
1296 EVEL_ERROR("Collector setup issue-retry count=%d", collector_down_count);
1305 sleep(EVEL_COLLECTOR_RECONNECTION_WAIT_TIME);
1306 collector_down_count = collector_down_count + 1;
1307 EVEL_ERROR("Collector setup issue-retry count=%d", collector_down_count);
1310 rc = evel_send_to_another_collector(msg->event_domain, json_body, json_size);
1313 if ((rc == EVEL_SUCCESS) && ((http_response_code / 100) != 2))
1316 if (http_response_code == 400) // 400 - Bad JSON related return code
1319 if ((rc != EVEL_SUCCESS) || (switch_coll == 1))
1321 collector_down_count = collector_down_count + 1;
1322 EVEL_ERROR("Collector setup issue-retry count=%d", collector_down_count);
1331 else if (msg->event_domain != EVEL_DOMAIN_INTERNAL )
1333 EVEL_DEBUG("External event received");
1335 /***********************************************************************/
1336 /* Encode the event in JSON. */
1337 /***********************************************************************/
1338 json_size = evel_json_encode_event(json_body, EVEL_MAX_JSON_BODY, msg);
1340 /***************************************************************************/
1341 /* Set the URL for the API. */
1342 /***************************************************************************/
1343 if (evel_collector_id == 1)
1344 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_event_api_url);
1346 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_bevent_api_url);
1347 if (curl_rc != CURLE_OK)
1349 rc = EVEL_CURL_LIBRARY_FAIL;
1350 log_error_state("Failed to initialize libCURL with the API URL. "
1351 "Error code=%d (%s)", curl_rc, curl_err_string);
1354 /***********************************************************************/
1355 /* Send the JSON across the API. */
1356 /***********************************************************************/
1357 EVEL_DEBUG("Sending JSON of size %d is: %s", json_size, json_body);
1358 rc = evel_post_api(json_body, json_size);
1361 if ((rc == EVEL_SUCCESS) && ((http_response_code / 100) != 2))
1364 if (http_response_code == 400) // 400 - Bad JSON related return code
1368 if ((rc != EVEL_SUCCESS) || (switch_coll == 1))
1370 EVEL_ERROR("Failed to transfer the data. Error code=%d", rc);
1371 EVEL_DEBUG("Switching to other collector if any");
1375 if (curr_global_handles == 2)
1377 rc = evel_send_to_another_collector(msg->event_domain, json_body, json_size);
1380 if ((rc == EVEL_SUCCESS) && ((http_response_code / 100) != 2))
1383 if (http_response_code == 400) // 400 - Bad JSON related return code
1386 if ((rc != EVEL_SUCCESS) || (switch_coll == 1))
1388 sleep(EVEL_COLLECTOR_RECONNECTION_WAIT_TIME);
1389 collector_down_count = collector_down_count + 1;
1390 EVEL_ERROR("Collector setup issue-retry count=%d", collector_down_count);
1399 sleep(EVEL_COLLECTOR_RECONNECTION_WAIT_TIME);
1400 collector_down_count = collector_down_count + 1;
1401 EVEL_ERROR("Collector setup issue-retry count=%d", collector_down_count);
1404 rc = evel_send_to_another_collector(msg->event_domain, json_body, json_size);
1407 if ((rc == EVEL_SUCCESS) && ((http_response_code / 100) != 2))
1410 if (http_response_code == 400) // 400 - Bad JSON related return code
1413 if ((rc != EVEL_SUCCESS) || (switch_coll == 1))
1415 collector_down_count = collector_down_count + 1;
1416 EVEL_ERROR("Collector setup issue-retry count=%d", collector_down_count);
1427 EVEL_DEBUG("Internal event received");
1428 internal_msg = (EVENT_INTERNAL *) msg;
1429 assert(internal_msg->command == EVT_CMD_TERMINATE);
1430 evt_handler_state = EVT_HANDLER_TERMINATING;
1433 /*************************************************************************/
1434 /* We are responsible for freeing the memory. */
1435 /*************************************************************************/
1436 evel_free_event(msg);
1439 /*************************************************************************/
1440 /* There may be a single priority post to be sent. */
1441 /*************************************************************************/
1442 if (priority_post.memory != NULL)
1444 EVEL_DEBUG("Priority Post");
1446 /***********************************************************************/
1447 /* Set the URL for the throttling API. */
1448 /***********************************************************************/
1449 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_throt_api_url);
1450 if (curl_rc != CURLE_OK)
1452 /*********************************************************************/
1453 /* This is only likely to happen with CURLE_OUT_OF_MEMORY, in which */
1454 /* case we carry on regardless. */
1455 /*********************************************************************/
1456 EVEL_ERROR("Failed to set throttling URL. Error code=%d", rc);
1460 rc = evel_post_api(priority_post.memory, priority_post.size);
1461 if (rc != EVEL_SUCCESS)
1463 EVEL_ERROR("Failed to transfer priority post. Error code=%d", rc);
1467 /***********************************************************************/
1468 /* Reinstate the URL for the event API. */
1469 /***********************************************************************/
1470 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_event_api_url);
1471 if (curl_rc != CURLE_OK)
1473 /*********************************************************************/
1474 /* This is only likely to happen with CURLE_OUT_OF_MEMORY, in which */
1475 /* case we carry on regardless. */
1476 /*********************************************************************/
1477 EVEL_ERROR("Failed to reinstate events URL. Error code=%d", rc);
1480 /***********************************************************************/
1481 /* We are responsible for freeing the memory. */
1482 /***********************************************************************/
1483 free(priority_post.memory);
1484 priority_post.memory = NULL;
1488 /***************************************************************************/
1489 /* The event handler is now exiting. The ring-buffer could contain events */
1490 /* which have not been processed, so deplete those. Because we've been */
1491 /* asked to exit we can be confident that the foreground will have stopped */
1492 /* sending events in so we know that this process will conclude! */
1493 /***************************************************************************/
1494 evt_handler_state = EVT_HANDLER_TERMINATING;
1495 while (!ring_buffer_is_empty(&event_buffer))
1497 EVEL_DEBUG("Reading event from buffer");
1498 msg = ring_buffer_read(&event_buffer);
1499 evel_free_event(msg);
1501 evt_handler_state = EVT_HANDLER_TERMINATED;
1502 EVEL_INFO("Event handler thread stopped");
1507 /**************************************************************************//**
1508 * Handle a JSON response from the listener, contained in a ::MEMORY_CHUNK.
1510 * Tokenize the response, and decode any tokens found.
1512 * @param chunk The memory chunk containing the response.
1513 * @param post The memory chunk in which to place any resulting POST.
1514 *****************************************************************************/
1515 void evel_handle_event_response(const MEMORY_CHUNK * const chunk,
1516 MEMORY_CHUNK * const post)
1518 jsmn_parser json_parser;
1519 jsmntok_t json_tokens[EVEL_MAX_RESPONSE_TOKENS];
1524 /***************************************************************************/
1525 /* Check preconditions. */
1526 /***************************************************************************/
1527 assert(chunk != NULL);
1528 assert(priority_post.memory == NULL);
1530 EVEL_DEBUG("Response size = %d", chunk->size);
1531 EVEL_DEBUG("Response = %s", chunk->memory);
1533 /***************************************************************************/
1534 /* Initialize the parser and tokenize the response. */
1535 /***************************************************************************/
1536 jsmn_init(&json_parser);
1537 num_tokens = jsmn_parse(&json_parser,
1541 EVEL_MAX_RESPONSE_TOKENS);
1545 EVEL_ERROR("Failed to parse JSON response. "
1546 "Error code=%d", num_tokens);
1548 else if (num_tokens == 0)
1550 EVEL_DEBUG("No tokens found in JSON response");
1554 EVEL_DEBUG("Decode JSON response tokens");
1555 if (!evel_handle_response_tokens(chunk, json_tokens, num_tokens, post))
1557 EVEL_ERROR("Failed to handle JSON response.");
1564 /**************************************************************************//**
1565 * Handle a JSON response from the listener, as a list of tokens from JSMN.
1567 * @param chunk Memory chunk containing the JSON buffer.
1568 * @param json_tokens Array of tokens to handle.
1569 * @param num_tokens The number of tokens to handle.
1570 * @param post The memory chunk in which to place any resulting POST.
1571 * @return true if we handled the response, false otherwise.
1572 *****************************************************************************/
1573 bool evel_handle_response_tokens(const MEMORY_CHUNK * const chunk,
1574 const jsmntok_t * const json_tokens,
1575 const int num_tokens,
1576 MEMORY_CHUNK * const post)
1578 bool json_ok = true;
1582 /***************************************************************************/
1583 /* Check preconditions. */
1584 /***************************************************************************/
1585 assert(chunk != NULL);
1586 assert(json_tokens != NULL);
1587 assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS);
1589 /***************************************************************************/
1590 /* Peek at the tokens to decide what the response it, then call the */
1591 /* appropriate handler to handle it. There is only one handler at this */
1593 /***************************************************************************/
1594 if (evel_tokens_match_command_list(chunk, json_tokens, num_tokens))
1596 json_ok = evel_handle_command_list(chunk, json_tokens, num_tokens, post);
1604 /**************************************************************************//**
1605 * Determine whether a list of tokens looks like a "commandList" response.
1607 * @param chunk Memory chunk containing the JSON buffer.
1608 * @param json_tokens Token to check.
1609 * @param num_tokens The number of tokens to handle.
1610 * @return true if the tokens look like a "commandList" match, or false.
1611 *****************************************************************************/
1612 bool evel_tokens_match_command_list(const MEMORY_CHUNK * const chunk,
1613 const jsmntok_t * const json_tokens,
1614 const int num_tokens)
1616 bool result = false;
1620 /***************************************************************************/
1621 /* Make some checks on the basic layout of the commandList. */
1622 /***************************************************************************/
1623 if ((num_tokens > 3) &&
1624 (json_tokens[0].type == JSMN_OBJECT) &&
1625 (json_tokens[1].type == JSMN_STRING) &&
1626 (json_tokens[2].type == JSMN_ARRAY) &&
1627 (evel_token_equals_string(chunk, &json_tokens[1], "commandList")))
1637 /**************************************************************************//**
1638 * Check that a string token matches a given input string.
1640 * @param chunk Memory chunk containing the JSON buffer.
1641 * @param json_token Token to check.
1642 * @param check_string String to check it against.
1643 * @return true if the strings match, or false.
1644 *****************************************************************************/
1645 bool evel_token_equals_string(const MEMORY_CHUNK * const chunk,
1646 const jsmntok_t * json_token,
1647 const char * check_string)
1649 bool result = false;
1653 const int token_length = json_token->end - json_token->start;
1654 const char * const token_string = chunk->memory + json_token->start;
1656 if (token_length == (int)strlen(check_string))
1658 result = (strncmp(token_string, check_string, token_length) == 0);