From 3426556541256f93d2cba65df3b9c8d1d1772861 Mon Sep 17 00:00:00 2001 From: platania Date: Thu, 16 Feb 2017 11:20:22 -0500 Subject: Initial OpenECOMP Demo commit Change-Id: Ibf8696196a7ac2c84ac8aa7cde1982c9c89fb64d Signed-off-by: platania --- vnfs/VES/code/evel_library/double_list.c | 194 ++ vnfs/VES/code/evel_library/double_list.h | 70 + vnfs/VES/code/evel_library/evel.c | 395 +++ vnfs/VES/code/evel_library/evel.h | 3677 ++++++++++++++++++++ vnfs/VES/code/evel_library/evel_event.c | 568 +++ vnfs/VES/code/evel_library/evel_event_mgr.c | 1053 ++++++ vnfs/VES/code/evel_library/evel_fault.c | 337 ++ vnfs/VES/code/evel_library/evel_internal.h | 867 +++++ vnfs/VES/code/evel_library/evel_internal_event.c | 124 + vnfs/VES/code/evel_library/evel_json_buffer.c | 853 +++++ vnfs/VES/code/evel_library/evel_logging.c | 181 + vnfs/VES/code/evel_library/evel_mobile_flow.c | 2036 +++++++++++ vnfs/VES/code/evel_library/evel_option.c | 442 +++ vnfs/VES/code/evel_library/evel_other.c | 231 ++ .../code/evel_library/evel_reporting_measurement.c | 450 +++ .../code/evel_library/evel_scaling_measurement.c | 1711 +++++++++ vnfs/VES/code/evel_library/evel_service.c | 1313 +++++++ vnfs/VES/code/evel_library/evel_signaling.c | 509 +++ vnfs/VES/code/evel_library/evel_state_change.c | 295 ++ vnfs/VES/code/evel_library/evel_strings.c | 477 +++ vnfs/VES/code/evel_library/evel_syslog.c | 500 +++ vnfs/VES/code/evel_library/evel_throttle.c | 2114 +++++++++++ vnfs/VES/code/evel_library/evel_throttle.h | 228 ++ vnfs/VES/code/evel_library/jsmn.c | 311 ++ vnfs/VES/code/evel_library/jsmn.h | 76 + vnfs/VES/code/evel_library/license.md | 95 + vnfs/VES/code/evel_library/metadata.c | 607 ++++ vnfs/VES/code/evel_library/metadata.h | 72 + vnfs/VES/code/evel_library/quickstart.md | 445 +++ vnfs/VES/code/evel_library/readme.md | 236 ++ vnfs/VES/code/evel_library/ring_buffer.c | 206 ++ vnfs/VES/code/evel_library/ring_buffer.h | 109 + 32 files changed, 20782 insertions(+) create mode 100644 vnfs/VES/code/evel_library/double_list.c create mode 100644 vnfs/VES/code/evel_library/double_list.h create mode 100644 vnfs/VES/code/evel_library/evel.c create mode 100644 vnfs/VES/code/evel_library/evel.h create mode 100644 vnfs/VES/code/evel_library/evel_event.c create mode 100644 vnfs/VES/code/evel_library/evel_event_mgr.c create mode 100644 vnfs/VES/code/evel_library/evel_fault.c create mode 100644 vnfs/VES/code/evel_library/evel_internal.h create mode 100644 vnfs/VES/code/evel_library/evel_internal_event.c create mode 100644 vnfs/VES/code/evel_library/evel_json_buffer.c create mode 100644 vnfs/VES/code/evel_library/evel_logging.c create mode 100644 vnfs/VES/code/evel_library/evel_mobile_flow.c create mode 100644 vnfs/VES/code/evel_library/evel_option.c create mode 100644 vnfs/VES/code/evel_library/evel_other.c create mode 100644 vnfs/VES/code/evel_library/evel_reporting_measurement.c create mode 100644 vnfs/VES/code/evel_library/evel_scaling_measurement.c create mode 100644 vnfs/VES/code/evel_library/evel_service.c create mode 100644 vnfs/VES/code/evel_library/evel_signaling.c create mode 100644 vnfs/VES/code/evel_library/evel_state_change.c create mode 100644 vnfs/VES/code/evel_library/evel_strings.c create mode 100644 vnfs/VES/code/evel_library/evel_syslog.c create mode 100644 vnfs/VES/code/evel_library/evel_throttle.c create mode 100644 vnfs/VES/code/evel_library/evel_throttle.h create mode 100644 vnfs/VES/code/evel_library/jsmn.c create mode 100644 vnfs/VES/code/evel_library/jsmn.h create mode 100644 vnfs/VES/code/evel_library/license.md create mode 100644 vnfs/VES/code/evel_library/metadata.c create mode 100644 vnfs/VES/code/evel_library/metadata.h create mode 100644 vnfs/VES/code/evel_library/quickstart.md create mode 100644 vnfs/VES/code/evel_library/readme.md create mode 100644 vnfs/VES/code/evel_library/ring_buffer.c create mode 100644 vnfs/VES/code/evel_library/ring_buffer.h (limited to 'vnfs/VES/code/evel_library') diff --git a/vnfs/VES/code/evel_library/double_list.c b/vnfs/VES/code/evel_library/double_list.c new file mode 100644 index 00000000..a480accb --- /dev/null +++ b/vnfs/VES/code/evel_library/double_list.c @@ -0,0 +1,194 @@ +/**************************************************************************//** + * @file + * A simple double-linked list. + * + * @note No thread protection so you will need to use appropriate + * synchronization if use spans multiple threads. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include + +#include "double_list.h" +#include "evel.h" + +/**************************************************************************//** + * List initialization. + * + * Initialize the list supplied to be empty. + * + * @param list Pointer to the list to be initialized. + + * @returns Nothing +******************************************************************************/ +void dlist_initialize(DLIST * list) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(list != NULL); + + /***************************************************************************/ + /* Initialize the list as empty. */ + /***************************************************************************/ + list->head = NULL; + list->tail = NULL; + + EVEL_EXIT(); +} + +void * dlist_pop_last(DLIST * list) +{ + void *item = NULL; + DLIST_ITEM *current_tail = NULL; + DLIST_ITEM *new_tail = NULL; + + assert(list != NULL); + + current_tail = list->tail; + if (current_tail != NULL) + { + item = current_tail->item; + new_tail = current_tail->previous; + if (new_tail == NULL) + { + list->head = NULL; + list->tail = NULL; + } + else + { + new_tail->next = NULL; + list->tail = new_tail; + } + free(current_tail); + } + + return item; +} + +void dlist_push_first(DLIST * list, void * item) +{ + DLIST_ITEM * new_element = NULL; + DLIST_ITEM * current_head = NULL; + + /***************************************************************************/ + /* Check assumptions. Note that we do allow putting NULL pointers into */ + /* the list - not sure you'd want to, but let it happen. */ + /***************************************************************************/ + assert(list != NULL); + + current_head = list->head; + + new_element = malloc(sizeof(DLIST_ITEM)); + assert(new_element != NULL); + new_element->next = current_head; + new_element->previous = NULL; + new_element->item = item; + list->head = new_element; + + if (current_head != NULL) + { + current_head->previous = new_element; + } + else + { + list->tail = new_element; + } +} + +void dlist_push_last(DLIST * list, void * item) +{ + DLIST_ITEM * new_element = NULL; + DLIST_ITEM * current_tail = NULL; + + /***************************************************************************/ + /* Check assumptions. Note that we do allow putting NULL pointers into */ + /* the list - not sure you'd want to, but let it happen. */ + /***************************************************************************/ + assert(list != NULL); + + current_tail = list->tail; + + new_element = malloc(sizeof(DLIST_ITEM)); + assert(new_element != NULL); + new_element->next = NULL; + new_element->previous = current_tail; + new_element->item = item; + list->tail = new_element; + + if (current_tail != NULL) + { + current_tail->next = new_element; + } + else + { + list->head = new_element; + } +} + +DLIST_ITEM * dlist_get_first(DLIST * list) +{ + return list->head; +} + +DLIST_ITEM * dlist_get_last(DLIST * list) +{ + return list->tail; +} + +DLIST_ITEM * dlist_get_next(DLIST_ITEM * item) +{ + return item->next; +} + +int dlist_is_empty(DLIST * list) +{ + return (list->head == NULL); +} + +int dlist_count(DLIST * list) +{ + int count = 0; + DLIST_ITEM * item = list->head; + + while (item != NULL) + { + count++; + item = item->next; + } + + return count; +} diff --git a/vnfs/VES/code/evel_library/double_list.h b/vnfs/VES/code/evel_library/double_list.h new file mode 100644 index 00000000..e8bdd742 --- /dev/null +++ b/vnfs/VES/code/evel_library/double_list.h @@ -0,0 +1,70 @@ +#ifndef DOUBLE_LIST_INCLUDED +#define DOUBLE_LIST_INCLUDED + +/**************************************************************************//** + * @file + * A simple double-linked list. + * + * @note No thread protection so you will need to use appropriate + * synchronization if use spans multiple threads. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*****************************************************************************/ + +typedef struct dlist_item +{ + struct dlist_item * previous; + struct dlist_item * next; + void * item; +} DLIST_ITEM; + +/**************************************************************************//** + * Double-linked list structure + *****************************************************************************/ +typedef struct dlist +{ + DLIST_ITEM * head; + DLIST_ITEM * tail; +} DLIST; + + +void dlist_initialize(DLIST * list); +void * dlist_pop_last(DLIST * list); +void dlist_push_first(DLIST * list, void * item); +void dlist_push_last(DLIST * list, void * item); +DLIST_ITEM * dlist_get_first(DLIST * list); +DLIST_ITEM * dlist_get_last(DLIST * list); +DLIST_ITEM * dlist_get_next(DLIST_ITEM * item); +int dlist_is_empty(DLIST * list); +int dlist_count(DLIST * list); + +#endif diff --git a/vnfs/VES/code/evel_library/evel.c b/vnfs/VES/code/evel_library/evel.c new file mode 100644 index 00000000..3380cace --- /dev/null +++ b/vnfs/VES/code/evel_library/evel.c @@ -0,0 +1,395 @@ +/**************************************************************************//** + * @file + * Source module isolating the ECOMP Vendor Event Listener (EVEL) API. + * + * This file implements the EVEL library which is intended to provide a + * simple wrapper around the complexity of AT&T's Vendor Event Listener API so + * that VNFs can use it without worrying about details of: + * + * * The API's encoding into JSON. + * * The API's transport over HTTP/HTTPS. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "evel.h" +#include "evel_internal.h" +#include "evel_throttle.h" +#include "metadata.h" + +/**************************************************************************//** + * The type of equipment represented by this VNF. + *****************************************************************************/ +EVEL_SOURCE_TYPES event_source_type = EVEL_SOURCE_OTHER; + +/**************************************************************************//** + * The Functional Role of the equipment represented by this VNF. + *****************************************************************************/ +char *functional_role = NULL; + +/**************************************************************************//** + * Library initialization. + * + * Initialize the EVEL library. + * + * @note This function initializes the cURL library. Applications making use + * of libcurl may need to pull the initialization out of here. Note + * also that this function is not threadsafe as a result - refer to + * libcurl's API documentation for relevant warnings. + * + * @sa Matching Term function. + * + * @param fqdn The API's FQDN or IP address. + * @param port The API's port. + * @param path The optional path (may be NULL). + * @param topic The optional topic part of the URL (may be NULL). + * @param secure Whether to use HTTPS (0=HTTP, 1=HTTPS) + * @param username Username for Basic Authentication of requests. + * @param password Password for Basic Authentication of requests. + * @param source_type The kind of node we represent. + * @param role The role this node undertakes. + * @param verbosity 0 for normal operation, positive values for chattier + * logs. + * + * @returns Status code + * @retval EVEL_SUCCESS On success + * @retval ::EVEL_ERR_CODES On failure. + *****************************************************************************/ +EVEL_ERR_CODES evel_initialize(const char * const fqdn, + int port, + const char * const path, + const char * const topic, + int secure, + const char * const username, + const char * const password, + EVEL_SOURCE_TYPES source_type, + const char * const role, + int verbosity + ) +{ + EVEL_ERR_CODES rc = EVEL_SUCCESS; + char base_api_url[EVEL_MAX_URL_LEN + 1] = {0}; + char event_api_url[EVEL_MAX_URL_LEN + 1] = {0}; + char throt_api_url[EVEL_MAX_URL_LEN + 1] = {0}; + char path_url[EVEL_MAX_URL_LEN + 1] = {0}; + char topic_url[EVEL_MAX_URL_LEN + 1] = {0}; + char version_string[10] = {0}; + int offset; + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(fqdn != NULL); + assert(port > 0 && port <= 65535); + assert(source_type < EVEL_MAX_SOURCE_TYPES); + assert(role != NULL); + + /***************************************************************************/ + /* Start logging so we can report on progress. */ + /***************************************************************************/ + log_initialize(verbosity == 0 ? EVEL_LOG_INFO : EVEL_LOG_DEBUG, "EVEL"); + EVEL_INFO("EVEL started"); + EVEL_INFO("API server is: %s", fqdn); + EVEL_INFO("API port is: %d", port); + + if (path != NULL) + { + EVEL_INFO("API path is: %s", path); + } + else + { + EVEL_INFO("No API path"); + } + + if (topic != NULL) + { + EVEL_INFO("API topic is: %s", topic); + } + else + { + EVEL_INFO("No API topic"); + } + + EVEL_INFO("API transport is: %s", secure ? "HTTPS" : "HTTP"); + EVEL_INFO("Event Source Type is: %d", source_type); + EVEL_INFO("Functional Role is: %s", role); + EVEL_INFO("Log verbosity is: %d", verbosity); + + /***************************************************************************/ + /* Initialize event throttling to the default state. */ + /***************************************************************************/ + evel_throttle_initialize(); + + /***************************************************************************/ + /* Save values we will need during operation. */ + /***************************************************************************/ + event_source_type = source_type; + functional_role = strdup(role); + + /***************************************************************************/ + /* Ensure there are no trailing zeroes and unnecessary decimal points in */ + /* the version. */ + /***************************************************************************/ + offset = sprintf(version_string, "%d", EVEL_API_MAJOR_VERSION); + + if (EVEL_API_MINOR_VERSION != 0) + { + sprintf(version_string + offset, ".%d", EVEL_API_MINOR_VERSION); + } + + /***************************************************************************/ + /* Build a common base of the API URLs. */ + /***************************************************************************/ + strcpy(path_url, "/"); + snprintf(base_api_url, + EVEL_MAX_URL_LEN, + "%s://%s:%d%s/eventListener/v%s", + secure ? "https" : "http", + fqdn, + port, + (((path != NULL) && (strlen(path) > 0)) ? + strncat(path_url, path, EVEL_MAX_URL_LEN) : ""), + version_string); + + /***************************************************************************/ + /* Build the URL to the event API. */ + /***************************************************************************/ + strcpy(topic_url, "/"); + snprintf(event_api_url, + EVEL_MAX_URL_LEN, + "%s%s", + base_api_url, + (((topic != NULL) && (strlen(topic) > 0)) ? + strncat(topic_url, topic, EVEL_MAX_URL_LEN) : "")); + EVEL_INFO("Vendor Event Listener API is located at: %s", event_api_url); + + /***************************************************************************/ + /* Build the URL to the throttling API. */ + /***************************************************************************/ + snprintf(throt_api_url, + EVEL_MAX_URL_LEN, + "%s/clientThrottlingState", + base_api_url); + EVEL_INFO("Vendor Event Throttling API is located at: %s", throt_api_url); + + /***************************************************************************/ + /* Spin-up the event-handler, which gets cURL readied for use. */ + /***************************************************************************/ + rc = event_handler_initialize(event_api_url, + throt_api_url, + username, + password, + verbosity); + if (rc != EVEL_SUCCESS) + { + log_error_state("Failed to initialize event handler (including cURL)"); + goto exit_label; + } + + /***************************************************************************/ + /* Extract the metadata from OpenStack. If we fail to extract it, we */ + /* record that in the logs, but carry on, assuming we're in a test */ + /* without a metadata service. */ + /***************************************************************************/ + rc = openstack_metadata(verbosity); + if (rc != EVEL_SUCCESS) + { + EVEL_INFO("Failed to load OpenStack metadata - assuming test environment"); + rc = EVEL_SUCCESS; + } + + /***************************************************************************/ + /* Start the event handler thread. */ + /***************************************************************************/ + rc = event_handler_run(); + if (rc != EVEL_SUCCESS) + { + log_error_state("Failed to start event handler thread. " + "Error code=%d", rc); + goto exit_label; + } + +exit_label: + return(rc); +} + +/**************************************************************************//** + * Clean up the EVEL library. + * + * @note that at present don't expect Init/Term cycling not to leak memory! + * + * @returns Status code + * @retval EVEL_SUCCESS On success + * @retval "One of ::EVEL_ERR_CODES" On failure. + *****************************************************************************/ +EVEL_ERR_CODES evel_terminate(void) +{ + int rc = EVEL_SUCCESS; + + /***************************************************************************/ + /* First terminate any pending transactions in the event-posting thread. */ + /***************************************************************************/ + rc = event_handler_terminate(); + if (rc != EVEL_SUCCESS) + { + log_error_state("Failed to terminate EVEL library cleanly!"); + } + + /***************************************************************************/ + /* Shut down the Event Handler library in a tidy manner. */ + /***************************************************************************/ + curl_global_cleanup(); + + /***************************************************************************/ + /* Clean up allocated memory. */ + /***************************************************************************/ + free(functional_role); + + /***************************************************************************/ + /* Clean up event throttling. */ + /***************************************************************************/ + evel_throttle_terminate(); + + EVEL_INFO("EVEL stopped"); + return(rc); +} + +/**************************************************************************//** + * Free an event. + * + * Free off the event supplied. Will free all the contained allocated memory. + * + * @note It is safe to free a NULL pointer. + *****************************************************************************/ +void evel_free_event(void * event) +{ + EVENT_HEADER * evt_ptr = event; + EVEL_ENTER(); + + if (event != NULL) + { + /*************************************************************************/ + /* Work out what kind of event we're dealing with so we can cast it */ + /* appropriately. */ + /*************************************************************************/ + switch (evt_ptr->event_domain) + { + case EVEL_DOMAIN_INTERNAL: + EVEL_DEBUG("Event is an Internal event at %lp", evt_ptr); + evel_free_internal_event((EVENT_INTERNAL *) evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_INTERNAL)); + free(evt_ptr); + break; + + case EVEL_DOMAIN_HEARTBEAT: + EVEL_DEBUG("Event is a Heartbeat at %lp", evt_ptr); + evel_free_header(evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_HEADER)); + free(evt_ptr); + break; + + case EVEL_DOMAIN_FAULT: + EVEL_DEBUG("Event is a Fault at %lp", evt_ptr); + evel_free_fault((EVENT_FAULT *)evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_FAULT)); + free(evt_ptr); + break; + + case EVEL_DOMAIN_MEASUREMENT: + EVEL_DEBUG("Event is a Measurement at %lp", evt_ptr); + evel_free_measurement((EVENT_MEASUREMENT *)evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_MEASUREMENT)); + free(evt_ptr); + break; + + case EVEL_DOMAIN_MOBILE_FLOW: + EVEL_DEBUG("Event is a Mobile Flow at %lp", evt_ptr); + evel_free_mobile_flow((EVENT_MOBILE_FLOW *)evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_MOBILE_FLOW)); + free(evt_ptr); + break; + + case EVEL_DOMAIN_REPORT: + EVEL_DEBUG("Event is a Report at %lp", evt_ptr); + evel_free_report((EVENT_REPORT *)evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_REPORT)); + free(evt_ptr); + break; + + case EVEL_DOMAIN_SERVICE: + EVEL_DEBUG("Event is a Service Event at %lp", evt_ptr); + evel_free_service((EVENT_SERVICE *)evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_SERVICE)); + free(evt_ptr); + break; + + case EVEL_DOMAIN_SIGNALING: + EVEL_DEBUG("Event is a Signaling at %lp", evt_ptr); + evel_free_signaling((EVENT_SIGNALING *)evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_SIGNALING)); + free(evt_ptr); + break; + + case EVEL_DOMAIN_STATE_CHANGE: + EVEL_DEBUG("Event is a State Change at %lp", evt_ptr); + evel_free_state_change((EVENT_STATE_CHANGE *)evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_STATE_CHANGE)); + free(evt_ptr); + break; + + case EVEL_DOMAIN_SYSLOG: + EVEL_DEBUG("Event is a Syslog at %lp", evt_ptr); + evel_free_syslog((EVENT_SYSLOG *)evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_SYSLOG)); + free(evt_ptr); + break; + + case EVEL_DOMAIN_OTHER: + EVEL_DEBUG("Event is an Other at %lp", evt_ptr); + evel_free_other((EVENT_OTHER *)evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_OTHER)); + free(evt_ptr); + break; + + default: + EVEL_ERROR("Unexpected event domain (%d)", evt_ptr->event_domain); + assert(0); + } + } + EVEL_EXIT(); +} diff --git a/vnfs/VES/code/evel_library/evel.h b/vnfs/VES/code/evel_library/evel.h new file mode 100644 index 00000000..a97dadc8 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel.h @@ -0,0 +1,3677 @@ +#ifndef EVEL_INCLUDED +#define EVEL_INCLUDED +/**************************************************************************//** + * @file + * Header for EVEL library + * + * This file implements the EVEL library which is intended to provide a + * simple wrapper around the complexity of AT&T's Vendor Event Listener API so + * that VNFs can use it without worrying about details of the API transport. + * + * Zero return value is success (::EVEL_SUCCESS), non-zero is failure and will + * be one of ::EVEL_ERR_CODES. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#include "double_list.h" + +/*****************************************************************************/ +/* Supported API version. */ +/*****************************************************************************/ +#define EVEL_API_MAJOR_VERSION 3 +#define EVEL_API_MINOR_VERSION 0 + +/**************************************************************************//** + * Error codes + * + * Error codes for EVEL low level interface + *****************************************************************************/ +typedef enum { + EVEL_SUCCESS, /** The operation was successful. */ + EVEL_ERR_GEN_FAIL, /** Non-specific failure. */ + EVEL_CURL_LIBRARY_FAIL, /** A cURL library operation failed. */ + EVEL_PTHREAD_LIBRARY_FAIL, /** A Posix threads operation failed. */ + EVEL_OUT_OF_MEMORY, /** A memory allocation failure occurred. */ + EVEL_EVENT_BUFFER_FULL, /** Too many events in the ring-buffer. */ + EVEL_EVENT_HANDLER_INACTIVE, /** Attempt to raise event when inactive. */ + EVEL_NO_METADATA, /** Failed to retrieve OpenStack metadata. */ + EVEL_BAD_METADATA, /** OpenStack metadata invalid format. */ + EVEL_BAD_JSON_FORMAT, /** JSON failed to parse correctly. */ + EVEL_JSON_KEY_NOT_FOUND, /** Failed to find the specified JSON key. */ + EVEL_MAX_ERROR_CODES /** Maximum number of valid error codes. */ +} EVEL_ERR_CODES; + +/**************************************************************************//** + * Logging levels + * + * Variable levels of verbosity in the logging functions. + *****************************************************************************/ +typedef enum { + EVEL_LOG_MIN = 0, + EVEL_LOG_SPAMMY = 30, + EVEL_LOG_DEBUG = 40, + EVEL_LOG_INFO = 50, + EVEL_LOG_ERROR = 60, + EVEL_LOG_MAX = 101 +} EVEL_LOG_LEVELS; + +/*****************************************************************************/ +/* Maximum string lengths. */ +/*****************************************************************************/ +#define EVEL_MAX_STRING_LEN 4096 +#define EVEL_MAX_JSON_BODY 16000 +#define EVEL_MAX_ERROR_STRING_LEN 255 +#define EVEL_MAX_URL_LEN 511 + +/**************************************************************************//** + * This value represents there being no restriction on the reporting interval. + *****************************************************************************/ +static const int EVEL_MEASUREMENT_INTERVAL_UKNOWN = 0; + +/**************************************************************************//** + * How many events can be backed-up before we start dropping events on the + * floor. + * + * @note This value should be tuned in accordance with expected burstiness of + * the event load and the expected response time of the ECOMP event + * listener so that the probability of the buffer filling is suitably + * low. + *****************************************************************************/ +static const int EVEL_EVENT_BUFFER_DEPTH = 100; + +/*****************************************************************************/ +/* How many different IP Types-of-Service are supported. */ +/*****************************************************************************/ +#define EVEL_TOS_SUPPORTED 256 + +/**************************************************************************//** + * Event domains for the various events we support. + * JSON equivalent field: domain + *****************************************************************************/ +typedef enum { + EVEL_DOMAIN_INTERNAL, /** Internal event, not for external routing. */ + EVEL_DOMAIN_HEARTBEAT, /** A Heartbeat event (event header only). */ + EVEL_DOMAIN_FAULT, /** A Fault event. */ + EVEL_DOMAIN_MEASUREMENT, /** A Measurement for VF Scaling event. */ + EVEL_DOMAIN_MOBILE_FLOW, /** A Mobile Flow event. */ + EVEL_DOMAIN_REPORT, /** A Measurement for VF Reporting event. */ + EVEL_DOMAIN_SERVICE, /** A Service event. */ + EVEL_DOMAIN_SIGNALING, /** A Signaling event. */ + EVEL_DOMAIN_STATE_CHANGE, /** A State Change event. */ + EVEL_DOMAIN_SYSLOG, /** A Syslog event. */ + EVEL_DOMAIN_OTHER, /** Another event. */ + EVEL_MAX_DOMAINS /** Maximum number of recognized Event types. */ +} EVEL_EVENT_DOMAINS; + +/**************************************************************************//** + * Event priorities. + * JSON equivalent field: priority + *****************************************************************************/ +typedef enum { + EVEL_PRIORITY_HIGH, + EVEL_PRIORITY_MEDIUM, + EVEL_PRIORITY_NORMAL, + EVEL_PRIORITY_LOW, + EVEL_MAX_PRIORITIES +} EVEL_EVENT_PRIORITIES; + +/**************************************************************************//** + * Fault / Threshold severities. + * JSON equivalent field: eventSeverity + *****************************************************************************/ +typedef enum { + EVEL_SEVERITY_CRITICAL, + EVEL_SEVERITY_MAJOR, + EVEL_SEVERITY_MINOR, + EVEL_SEVERITY_WARNING, + EVEL_SEVERITY_NORMAL, + EVEL_MAX_SEVERITIES +} EVEL_SEVERITIES; + +/**************************************************************************//** + * Fault source types. + * JSON equivalent field: eventSourceType + *****************************************************************************/ +typedef enum { + EVEL_SOURCE_OTHER, + EVEL_SOURCE_ROUTER, + EVEL_SOURCE_SWITCH, + EVEL_SOURCE_HOST, + EVEL_SOURCE_CARD, + EVEL_SOURCE_PORT, + EVEL_SOURCE_SLOT_THRESHOLD, + EVEL_SOURCE_PORT_THRESHOLD, + EVEL_SOURCE_VIRTUAL_MACHINE, + EVEL_SOURCE_VIRTUAL_NETWORK_FUNCTION, + /***************************************************************************/ + /* START OF VENDOR-SPECIFIC VALUES */ + /* */ + /* Vendor-specific values should be added here, and handled appropriately */ + /* in evel_event.c. */ + /***************************************************************************/ + + /***************************************************************************/ + /* END OF VENDOR-SPECIFIC VALUES */ + /***************************************************************************/ + EVEL_MAX_SOURCE_TYPES +} EVEL_SOURCE_TYPES; + +/**************************************************************************//** + * Fault VNF Status. + * JSON equivalent field: vfStatus + *****************************************************************************/ +typedef enum { + EVEL_VF_STATUS_ACTIVE, + EVEL_VF_STATUS_IDLE, + EVEL_VF_STATUS_PREP_TERMINATE, + EVEL_VF_STATUS_READY_TERMINATE, + EVEL_VF_STATUS_REQ_TERMINATE, + EVEL_MAX_VF_STATUSES +} EVEL_VF_STATUSES; + +/**************************************************************************//** + * Counter criticalities. + * JSON equivalent field: criticality + *****************************************************************************/ +typedef enum { + EVEL_COUNTER_CRITICALITY_CRIT, + EVEL_COUNTER_CRITICALITY_MAJ, + EVEL_MAX_COUNTER_CRITICALITIES +} EVEL_COUNTER_CRITICALITIES; + +/**************************************************************************//** + * Alert actions. + * JSON equivalent field: alertAction + *****************************************************************************/ +typedef enum { + EVEL_ALERT_ACTION_CLEAR, + EVEL_ALERT_ACTION_CONT, + EVEL_ALERT_ACTION_SET, + EVEL_MAX_ALERT_ACTIONS +} EVEL_ALERT_ACTIONS; + +/**************************************************************************//** + * Alert types. + * JSON equivalent field: alertType + *****************************************************************************/ +typedef enum { + EVEL_ALERT_TYPE_CARD, + EVEL_ALERT_TYPE_ELEMENT, + EVEL_ALERT_TYPE_INTERFACE, + EVEL_ALERT_TYPE_SERVICE, + EVEL_MAX_ALERT_TYPES +} EVEL_ALERT_TYPES; + +/**************************************************************************//** + * Alert types. + * JSON equivalent fields: newState, oldState + *****************************************************************************/ +typedef enum { + EVEL_ENTITY_STATE_IN_SERVICE, + EVEL_ENTITY_STATE_MAINTENANCE, + EVEL_ENTITY_STATE_OUT_OF_SERVICE, + EVEL_MAX_ENTITY_STATES +} EVEL_ENTITY_STATE; + +/**************************************************************************//** + * Syslog facilities. + * JSON equivalent field: syslogFacility + *****************************************************************************/ +typedef enum { + EVEL_SYSLOG_FACILITY_KERNEL, + EVEL_SYSLOG_FACILITY_USER, + EVEL_SYSLOG_FACILITY_MAIL, + EVEL_SYSLOG_FACILITY_SYSTEM_DAEMON, + EVEL_SYSLOG_FACILITY_SECURITY_AUTH, + EVEL_SYSLOG_FACILITY_INTERNAL, + EVEL_SYSLOG_FACILITY_LINE_PRINTER, + EVEL_SYSLOG_FACILITY_NETWORK_NEWS, + EVEL_SYSLOG_FACILITY_UUCP, + EVEL_SYSLOG_FACILITY_CLOCK_DAEMON, + EVEL_SYSLOG_FACILITY_SECURITY_AUTH2, + EVEL_SYSLOG_FACILITY_FTP_DAEMON, + EVEL_SYSLOG_FACILITY_NTP, + EVEL_SYSLOG_FACILITY_LOG_AUDIT, + EVEL_SYSLOG_FACILITY_LOG_ALERT, + EVEL_SYSLOG_FACILITY_CLOCK_DAEMON2, + EVEL_SYSLOG_FACILITY_LOCAL0, + EVEL_SYSLOG_FACILITY_LOCAL1, + EVEL_SYSLOG_FACILITY_LOCAL2, + EVEL_SYSLOG_FACILITY_LOCAL3, + EVEL_SYSLOG_FACILITY_LOCAL4, + EVEL_SYSLOG_FACILITY_LOCAL5, + EVEL_SYSLOG_FACILITY_LOCAL6, + EVEL_SYSLOG_FACILITY_LOCAL7, + EVEL_MAX_SYSLOG_FACILITIES +} EVEL_SYSLOG_FACILITIES; + +/**************************************************************************//** + * TCP flags. + * JSON equivalent fields: tcpFlagCountList, tcpFlagList + *****************************************************************************/ +typedef enum { + EVEL_TCP_NS, + EVEL_TCP_CWR, + EVEL_TCP_ECE, + EVEL_TCP_URG, + EVEL_TCP_ACK, + EVEL_TCP_PSH, + EVEL_TCP_RST, + EVEL_TCP_SYN, + EVEL_TCP_FIN, + EVEL_MAX_TCP_FLAGS +} EVEL_TCP_FLAGS; + +/**************************************************************************//** + * Mobile QCI Classes of Service. + * JSON equivalent fields: mobileQciCosCountList, mobileQciCosList + *****************************************************************************/ +typedef enum { + + /***************************************************************************/ + /* UMTS Classes of Service. */ + /***************************************************************************/ + EVEL_QCI_COS_UMTS_CONVERSATIONAL, + EVEL_QCI_COS_UMTS_STREAMING, + EVEL_QCI_COS_UMTS_INTERACTIVE, + EVEL_QCI_COS_UMTS_BACKGROUND, + + /***************************************************************************/ + /* LTE Classes of Service. */ + /***************************************************************************/ + EVEL_QCI_COS_LTE_1, + EVEL_QCI_COS_LTE_2, + EVEL_QCI_COS_LTE_3, + EVEL_QCI_COS_LTE_4, + EVEL_QCI_COS_LTE_65, + EVEL_QCI_COS_LTE_66, + EVEL_QCI_COS_LTE_5, + EVEL_QCI_COS_LTE_6, + EVEL_QCI_COS_LTE_7, + EVEL_QCI_COS_LTE_8, + EVEL_QCI_COS_LTE_9, + EVEL_QCI_COS_LTE_69, + EVEL_QCI_COS_LTE_70, + EVEL_MAX_QCI_COS_TYPES +} EVEL_QCI_COS_TYPES; + +/**************************************************************************//** + * Service Event endpoint description + * JSON equivalent field: endpointDesc + *****************************************************************************/ +typedef enum { + EVEL_SERVICE_ENDPOINT_CALLEE, + EVEL_SERVICE_ENDPOINT_CALLER, + EVEL_MAX_SERVICE_ENDPOINT_DESC +} EVEL_SERVICE_ENDPOINT_DESC; + +/**************************************************************************//** + * Boolean type for EVEL library. + *****************************************************************************/ +typedef enum { + EVEL_FALSE, + EVEL_TRUE +} EVEL_BOOLEAN; + +/**************************************************************************//** + * Optional parameter holder for double. + *****************************************************************************/ +typedef struct evel_option_double +{ + double value; + EVEL_BOOLEAN is_set; +} EVEL_OPTION_DOUBLE; + +/**************************************************************************//** + * Optional parameter holder for string. + *****************************************************************************/ +typedef struct evel_option_string +{ + char * value; + EVEL_BOOLEAN is_set; +} EVEL_OPTION_STRING; + +/**************************************************************************//** + * Optional parameter holder for int. + *****************************************************************************/ +typedef struct evel_option_int +{ + int value; + EVEL_BOOLEAN is_set; +} EVEL_OPTION_INT; + +/**************************************************************************//** + * Optional parameter holder for unsigned long long. + *****************************************************************************/ +typedef struct evel_option_ull +{ + unsigned long long value; + EVEL_BOOLEAN is_set; +} EVEL_OPTION_ULL; + +/**************************************************************************//** + * Optional parameter holder for time_t. + *****************************************************************************/ +typedef struct evel_option_time +{ + time_t value; + EVEL_BOOLEAN is_set; +} EVEL_OPTION_TIME; + +/*****************************************************************************/ +/* Supported Common Event Header version. */ +/*****************************************************************************/ +#define EVEL_HEADER_MAJOR_VERSION 1 +#define EVEL_HEADER_MINOR_VERSION 2 + +/**************************************************************************//** + * Event header. + * JSON equivalent field: commonEventHeader + *****************************************************************************/ +typedef struct event_header { + /***************************************************************************/ + /* Version */ + /***************************************************************************/ + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + EVEL_EVENT_DOMAINS event_domain; + char * event_id; + char * source_name; + char * functional_role; + char * reporting_entity_name; + EVEL_EVENT_PRIORITIES priority; + unsigned long long start_epoch_microsec; + unsigned long long last_epoch_microsec; + int sequence; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + EVEL_OPTION_STRING event_type; + EVEL_OPTION_STRING source_id; + EVEL_OPTION_STRING reporting_entity_id; + +} EVENT_HEADER; + +/*****************************************************************************/ +/* Supported Fault version. */ +/*****************************************************************************/ +#define EVEL_FAULT_MAJOR_VERSION 1 +#define EVEL_FAULT_MINOR_VERSION 1 + +/**************************************************************************//** + * Fault. + * JSON equivalent field: faultFields + *****************************************************************************/ +typedef struct event_fault { + /***************************************************************************/ + /* Header and version */ + /***************************************************************************/ + EVENT_HEADER header; + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + EVEL_SEVERITIES event_severity; + EVEL_SOURCE_TYPES event_source_type; + char * alarm_condition; + char * specific_problem; + EVEL_VF_STATUSES vf_status; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + EVEL_OPTION_STRING alarm_interface_a; + DLIST additional_info; + +} EVENT_FAULT; + +/**************************************************************************//** + * Fault Additional Info. + * JSON equivalent field: alarmAdditionalInformation + *****************************************************************************/ +typedef struct fault_additional_info { + char * name; + char * value; +} FAULT_ADDL_INFO; + +/*****************************************************************************/ +/* Supported Measurement version. */ +/*****************************************************************************/ +#define EVEL_MEASUREMENT_MAJOR_VERSION 1 +#define EVEL_MEASUREMENT_MINOR_VERSION 1 + +/**************************************************************************//** + * Errors. + * JSON equivalent field: errors + *****************************************************************************/ +typedef struct measurement_errors { + int receive_discards; + int receive_errors; + int transmit_discards; + int transmit_errors; +} MEASUREMENT_ERRORS; + +/**************************************************************************//** + * Measurement. + * JSON equivalent field: measurementsForVfScalingFields + *****************************************************************************/ +typedef struct event_measurement { + /***************************************************************************/ + /* Header and version */ + /***************************************************************************/ + EVENT_HEADER header; + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + double measurement_interval; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + DLIST additional_measurements; + EVEL_OPTION_DOUBLE aggregate_cpu_usage; + DLIST codec_usage; + EVEL_OPTION_INT concurrent_sessions; + EVEL_OPTION_INT configured_entities; + DLIST cpu_usage; + MEASUREMENT_ERRORS * errors; + DLIST feature_usage; + DLIST filesystem_usage; + DLIST latency_distribution; + EVEL_OPTION_DOUBLE mean_request_latency; + EVEL_OPTION_DOUBLE memory_configured; + EVEL_OPTION_DOUBLE memory_used; + EVEL_OPTION_INT media_ports_in_use; + EVEL_OPTION_INT request_rate; + EVEL_OPTION_DOUBLE vnfc_scaling_metric; + DLIST vnic_usage; + +} EVENT_MEASUREMENT; + +/**************************************************************************//** + * CPU Usage. + * JSON equivalent field: cpuUsage + *****************************************************************************/ +typedef struct measurement_cpu_use { + char * id; + double usage; +} MEASUREMENT_CPU_USE; + +/**************************************************************************//** + * Filesystem Usage. + * JSON equivalent field: filesystemUsage + *****************************************************************************/ +typedef struct measurement_fsys_use { + char * filesystem_name; + double block_configured; + int block_iops; + double block_used; + double ephemeral_configured; + int ephemeral_iops; + double ephemeral_used; +} MEASUREMENT_FSYS_USE; + +/**************************************************************************//** + * Latency Bucket. + * JSON equivalent field: latencyBucketMeasure + *****************************************************************************/ +typedef struct measurement_latency_bucket { + int count; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + EVEL_OPTION_DOUBLE high_end; + EVEL_OPTION_DOUBLE low_end; + +} MEASUREMENT_LATENCY_BUCKET; + +/**************************************************************************//** + * Virtual NIC usage. + * JSON equivalent field: vNicUsage + *****************************************************************************/ +typedef struct measurement_vnic_use { + int bytes_in; + int bytes_out; + int packets_in; + int packets_out; + char * vnic_id; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + EVEL_OPTION_INT broadcast_packets_in; + EVEL_OPTION_INT broadcast_packets_out; + EVEL_OPTION_INT multicast_packets_in; + EVEL_OPTION_INT multicast_packets_out; + EVEL_OPTION_INT unicast_packets_in; + EVEL_OPTION_INT unicast_packets_out; + +} MEASUREMENT_VNIC_USE; + +/**************************************************************************//** + * Codec Usage. + * JSON equivalent field: codecsInUse + *****************************************************************************/ +typedef struct measurement_codec_use { + char * codec_id; + int number_in_use; +} MEASUREMENT_CODEC_USE; + +/**************************************************************************//** + * Feature Usage. + * JSON equivalent field: featuresInUse + *****************************************************************************/ +typedef struct measurement_feature_use { + char * feature_id; + int feature_utilization; +} MEASUREMENT_FEATURE_USE; + +/**************************************************************************//** + * Measurement Group. + * JSON equivalent field: additionalMeasurements + *****************************************************************************/ +typedef struct measurement_group { + char * name; + DLIST measurements; +} MEASUREMENT_GROUP; + +/**************************************************************************//** + * Custom Defined Measurement. + * JSON equivalent field: measurements + *****************************************************************************/ +typedef struct custom_measurement { + char * name; + char * value; +} CUSTOM_MEASUREMENT; + +/*****************************************************************************/ +/* Supported Report version. */ +/*****************************************************************************/ +#define EVEL_REPORT_MAJOR_VERSION 1 +#define EVEL_REPORT_MINOR_VERSION 1 + +/**************************************************************************//** + * Report. + * JSON equivalent field: measurementsForVfReportingFields + * + * @note This is an experimental event type and is not currently a formal part + * of AT&T's specification. + *****************************************************************************/ +typedef struct event_report { + /***************************************************************************/ + /* Header and version */ + /***************************************************************************/ + EVENT_HEADER header; + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + double measurement_interval; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + DLIST feature_usage; + DLIST measurement_groups; + +} EVENT_REPORT; + +/**************************************************************************//** + * Mobile GTP Per Flow Metrics. + * JSON equivalent field: gtpPerFlowMetrics + *****************************************************************************/ +typedef struct mobile_gtp_per_flow_metrics { + double avg_bit_error_rate; + double avg_packet_delay_variation; + int avg_packet_latency; + int avg_receive_throughput; + int avg_transmit_throughput; + int flow_activation_epoch; + int flow_activation_microsec; + int flow_deactivation_epoch; + int flow_deactivation_microsec; + time_t flow_deactivation_time; + char * flow_status; + int max_packet_delay_variation; + int num_activation_failures; + int num_bit_errors; + int num_bytes_received; + int num_bytes_transmitted; + int num_dropped_packets; + int num_l7_bytes_received; + int num_l7_bytes_transmitted; + int num_lost_packets; + int num_out_of_order_packets; + int num_packet_errors; + int num_packets_received_excl_retrans; + int num_packets_received_incl_retrans; + int num_packets_transmitted_incl_retrans; + int num_retries; + int num_timeouts; + int num_tunneled_l7_bytes_received; + int round_trip_time; + int time_to_first_byte; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + EVEL_OPTION_INT ip_tos_counts[EVEL_TOS_SUPPORTED]; + EVEL_OPTION_INT tcp_flag_counts[EVEL_MAX_TCP_FLAGS]; + EVEL_OPTION_INT qci_cos_counts[EVEL_MAX_QCI_COS_TYPES]; + EVEL_OPTION_INT dur_connection_failed_status; + EVEL_OPTION_INT dur_tunnel_failed_status; + EVEL_OPTION_STRING flow_activated_by; + EVEL_OPTION_TIME flow_activation_time; + EVEL_OPTION_STRING flow_deactivated_by; + EVEL_OPTION_STRING gtp_connection_status; + EVEL_OPTION_STRING gtp_tunnel_status; + EVEL_OPTION_INT large_packet_rtt; + EVEL_OPTION_DOUBLE large_packet_threshold; + EVEL_OPTION_INT max_receive_bit_rate; + EVEL_OPTION_INT max_transmit_bit_rate; + EVEL_OPTION_INT num_gtp_echo_failures; + EVEL_OPTION_INT num_gtp_tunnel_errors; + EVEL_OPTION_INT num_http_errors; + +} MOBILE_GTP_PER_FLOW_METRICS; + +/*****************************************************************************/ +/* Supported Mobile Flow version. */ +/*****************************************************************************/ +#define EVEL_MOBILE_FLOW_MAJOR_VERSION 1 +#define EVEL_MOBILE_FLOW_MINOR_VERSION 1 + +/**************************************************************************//** + * Mobile Flow. + * JSON equivalent field: mobileFlow + *****************************************************************************/ +typedef struct event_mobile_flow { + /***************************************************************************/ + /* Header and version */ + /***************************************************************************/ + EVENT_HEADER header; + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + char * flow_direction; + MOBILE_GTP_PER_FLOW_METRICS * gtp_per_flow_metrics; + char * ip_protocol_type; + char * ip_version; + char * other_endpoint_ip_address; + int other_endpoint_port; + char * reporting_endpoint_ip_addr; + int reporting_endpoint_port; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + EVEL_OPTION_STRING application_type; + EVEL_OPTION_STRING app_protocol_type; + EVEL_OPTION_STRING app_protocol_version; + EVEL_OPTION_STRING cid; + EVEL_OPTION_STRING connection_type; + EVEL_OPTION_STRING ecgi; + EVEL_OPTION_STRING gtp_protocol_type; + EVEL_OPTION_STRING gtp_version; + EVEL_OPTION_STRING http_header; + EVEL_OPTION_STRING imei; + EVEL_OPTION_STRING imsi; + EVEL_OPTION_STRING lac; + EVEL_OPTION_STRING mcc; + EVEL_OPTION_STRING mnc; + EVEL_OPTION_STRING msisdn; + EVEL_OPTION_STRING other_functional_role; + EVEL_OPTION_STRING rac; + EVEL_OPTION_STRING radio_access_technology; + EVEL_OPTION_STRING sac; + EVEL_OPTION_INT sampling_algorithm; + EVEL_OPTION_STRING tac; + EVEL_OPTION_STRING tunnel_id; + EVEL_OPTION_STRING vlan_id; + +} EVENT_MOBILE_FLOW; + +/**************************************************************************//** + * Other. + * JSON equivalent field: otherFields + *****************************************************************************/ +typedef struct event_other { + EVENT_HEADER header; + DLIST other_fields; + +} EVENT_OTHER; + +/**************************************************************************//** + * Other Field. + * JSON equivalent field: otherFields + *****************************************************************************/ +typedef struct other_field { + char * name; + char * value; +} OTHER_FIELD; + +/**************************************************************************//** + * Event Instance Identifier + * JSON equivalent field: eventInstanceIdentifier + *****************************************************************************/ +typedef struct evel_event_instance_id { + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + char * vendor_id; /* JSON: vendorId */ + char * event_id; /* JSON: eventId */ + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + EVEL_OPTION_STRING product_id; /* JSON: productId */ + EVEL_OPTION_STRING subsystem_id; /* JSON: subsystemId */ + EVEL_OPTION_STRING event_friendly_name; /* JSON: eventFriendlyName */ + +} EVEL_EVENT_INSTANCE_ID; + +/*****************************************************************************/ +/* Supported Service Events version. */ +/*****************************************************************************/ +#define EVEL_SERVICE_MAJOR_VERSION 1 +#define EVEL_SERVICE_MINOR_VERSION 1 + +/**************************************************************************//** + * Service Events. + * JSON equivalent field: serviceEventsFields + *****************************************************************************/ +typedef struct event_service { + /***************************************************************************/ + /* Header and version */ + /***************************************************************************/ + EVENT_HEADER header; + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + EVEL_EVENT_INSTANCE_ID instance_id; /* JSON: eventInstanceIdentifier */ + + /***************************************************************************/ + /* Optional fields. */ + /***************************************************************************/ + EVEL_OPTION_STRING correlator; /* JSON: correlator */ + DLIST additional_fields; /* JSON: additionalFields */ + + /***************************************************************************/ + /* Optional fields within JSON equivalent object: codecSelected */ + /***************************************************************************/ + EVEL_OPTION_STRING codec; /* JSON: codec */ + + /***************************************************************************/ + /* Optional fields within JSON equivalent object: codecSelectedTranscoding */ + /***************************************************************************/ + EVEL_OPTION_STRING callee_side_codec; /* JSON: calleeSideCodec */ + EVEL_OPTION_STRING caller_side_codec; /* JSON: callerSideCodec */ + + /***************************************************************************/ + /* Optional fields within JSON equivalent object: midCallRtcp */ + /***************************************************************************/ + EVEL_OPTION_STRING rtcp_data; /* JSON: rtcpData */ + + /***************************************************************************/ + /* Optional fields within JSON equivalent object: endOfCallVqmSummaries */ + /***************************************************************************/ + EVEL_OPTION_STRING adjacency_name; /* JSON: adjacencyName */ + EVEL_OPTION_STRING endpoint_description; /* JSON: endpointDescription */ + EVEL_OPTION_INT endpoint_jitter; /* JSON: endpointJitter */ + EVEL_OPTION_INT endpoint_rtp_oct_disc; /* JSON: endpointRtpOctetsDiscarded */ + EVEL_OPTION_INT endpoint_rtp_oct_recv; /* JSON: endpointRtpOctetsReceived */ + EVEL_OPTION_INT endpoint_rtp_oct_sent; /* JSON: endpointRtpOctetsSent */ + EVEL_OPTION_INT endpoint_rtp_pkt_disc;/* JSON: endpointRtpPacketsDiscarded */ + EVEL_OPTION_INT endpoint_rtp_pkt_recv; /* JSON: endpointRtpPacketsReceived */ + EVEL_OPTION_INT endpoint_rtp_pkt_sent; /* JSON: endpointRtpPacketsSent */ + EVEL_OPTION_INT local_jitter; /* JSON: localJitter */ + EVEL_OPTION_INT local_rtp_oct_disc; /* JSON: localRtpOctetsDiscarded */ + EVEL_OPTION_INT local_rtp_oct_recv; /* JSON: localRtpOctetsReceived */ + EVEL_OPTION_INT local_rtp_oct_sent; /* JSON: localRtpOctetsSent */ + EVEL_OPTION_INT local_rtp_pkt_disc; /* JSON: localRtpPacketsDiscarded */ + EVEL_OPTION_INT local_rtp_pkt_recv; /* JSON: localRtpPacketsReceived */ + EVEL_OPTION_INT local_rtp_pkt_sent; /* JSON: localRtpPacketsSent */ + EVEL_OPTION_DOUBLE mos_cqe; /* JSON: mosCqe */ + EVEL_OPTION_INT packets_lost; /* JSON: packetsLost */ + EVEL_OPTION_DOUBLE packet_loss_percent; /* JSON: packetLossPercent */ + EVEL_OPTION_INT r_factor; /* JSON: rFactor */ + EVEL_OPTION_INT round_trip_delay; /* JSON: roundTripDelay */ + + /***************************************************************************/ + /* Optional fields within JSON equivalent object: marker */ + /***************************************************************************/ + EVEL_OPTION_STRING phone_number; /* JSON: phoneNumber */ + +} EVENT_SERVICE; + +/*****************************************************************************/ +/* Supported Signaling version. */ +/*****************************************************************************/ +#define EVEL_SIGNALING_MAJOR_VERSION 1 +#define EVEL_SIGNALING_MINOR_VERSION 1 + +/**************************************************************************//** + * Signaling. + * JSON equivalent field: signalingFields + *****************************************************************************/ +typedef struct event_signaling { + /***************************************************************************/ + /* Header and version */ + /***************************************************************************/ + EVENT_HEADER header; + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + EVEL_EVENT_INSTANCE_ID instance_id; /* JSON: eventInstanceIdentifier */ + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + EVEL_OPTION_STRING correlator; /* JSON: correlator */ + EVEL_OPTION_STRING local_ip_address; /* JSON: localIpAddress */ + EVEL_OPTION_STRING local_port; /* JSON: localPort */ + EVEL_OPTION_STRING remote_ip_address; /* JSON: remoteIpAddress */ + EVEL_OPTION_STRING remote_port; /* JSON: remotePort */ + EVEL_OPTION_STRING compressed_sip; /* JSON: compressedSip */ + EVEL_OPTION_STRING summary_sip; /* JSON: summarySip */ + +} EVENT_SIGNALING; + +/*****************************************************************************/ +/* Supported State Change version. */ +/*****************************************************************************/ +#define EVEL_STATE_CHANGE_MAJOR_VERSION 1 +#define EVEL_STATE_CHANGE_MINOR_VERSION 1 + +/**************************************************************************//** + * State Change. + * JSON equivalent field: stateChangeFields + *****************************************************************************/ +typedef struct event_state_change { + /***************************************************************************/ + /* Header and version */ + /***************************************************************************/ + EVENT_HEADER header; + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + EVEL_ENTITY_STATE new_state; + EVEL_ENTITY_STATE old_state; + char * state_interface; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + DLIST additional_fields; + +} EVENT_STATE_CHANGE; + +/**************************************************************************//** + * State Change Additional Field. + * JSON equivalent field: additionalFields + *****************************************************************************/ +typedef struct state_change_additional_field { + char * name; + char * value; +} STATE_CHANGE_ADDL_FIELD; + +/*****************************************************************************/ +/* Supported Syslog version. */ +/*****************************************************************************/ +#define EVEL_SYSLOG_MAJOR_VERSION 1 +#define EVEL_SYSLOG_MINOR_VERSION 1 + +/**************************************************************************//** + * Syslog. + * JSON equivalent field: syslogFields + *****************************************************************************/ +typedef struct event_syslog { + /***************************************************************************/ + /* Header and version */ + /***************************************************************************/ + EVENT_HEADER header; + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + EVEL_SOURCE_TYPES event_source_type; + char * syslog_msg; + char * syslog_tag; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + DLIST additional_fields; + EVEL_OPTION_STRING event_source_host; + EVEL_OPTION_INT syslog_facility; + EVEL_OPTION_STRING syslog_proc; + EVEL_OPTION_INT syslog_proc_id; + EVEL_OPTION_STRING syslog_s_data; + EVEL_OPTION_INT syslog_ver; + +} EVENT_SYSLOG; + +/**************************************************************************//** + * Syslog Additional Field. + * JSON equivalent field: additionalFields + *****************************************************************************/ +typedef struct syslog_additional_field { + char * name; + char * value; +} SYSLOG_ADDL_FIELD; + +/**************************************************************************//** + * Copyright. + * JSON equivalent object: attCopyrightNotice + *****************************************************************************/ +typedef struct copyright { + char * useAndRedistribution; + char * condition1; + char * condition2; + char * condition3; + char * condition4; + char * disclaimerLine1; + char * disclaimerLine2; + char * disclaimerLine3; + char * disclaimerLine4; +} COPYRIGHT; + +/**************************************************************************//** + * Library initialization. + * + * Initialize the EVEL library. + * + * @note This function initializes the cURL library. Applications making use + * of libcurl may need to pull the initialization out of here. Note + * also that this function is not threadsafe as a result - refer to + * libcurl's API documentation for relevant warnings. + * + * @sa Matching Term function. + * + * @param fqdn The API's FQDN or IP address. + * @param port The API's port. + * @param path The optional path (may be NULL). + * @param topic The optional topic part of the URL (may be NULL). + * @param secure Whether to use HTTPS (0=HTTP, 1=HTTPS). + * @param username Username for Basic Authentication of requests. + * @param password Password for Basic Authentication of requests. + * @param source_type The kind of node we represent. + * @param role The role this node undertakes. + * @param verbosity 0 for normal operation, positive values for chattier + * logs. + * + * @returns Status code + * @retval EVEL_SUCCESS On success + * @retval ::EVEL_ERR_CODES On failure. + *****************************************************************************/ +EVEL_ERR_CODES evel_initialize(const char * const fqdn, + int port, + const char * const path, + const char * const topic, + int secure, + const char * const username, + const char * const password, + EVEL_SOURCE_TYPES source_type, + const char * const role, + int verbosity + ); + +/**************************************************************************//** + * Clean up the EVEL library. + * + * @note that at present don't expect Init/Term cycling not to leak memory! + * + * @returns Status code + * @retval EVEL_SUCCESS On success + * @retval "One of ::EVEL_ERR_CODES" On failure. + *****************************************************************************/ +EVEL_ERR_CODES evel_terminate(void); + +EVEL_ERR_CODES evel_post_event(EVENT_HEADER * event); +const char * evel_error_string(void); + + +/**************************************************************************//** + * Free an event. + * + * Free off the event supplied. Will free all the contained allocated memory. + * + * @note It is safe to free a NULL pointer. + *****************************************************************************/ +void evel_free_event(void * event); + +/**************************************************************************//** + * Encode the event as a JSON event object according to AT&T's schema. + * + * @param json Pointer to where to store the JSON encoded data. + * @param max_size Size of storage available in json_body. + * @param event Pointer to the ::EVENT_HEADER to encode. + * @returns Number of bytes actually written. + *****************************************************************************/ +int evel_json_encode_event(char * json, + int max_size, + EVENT_HEADER * event); + +/**************************************************************************//** + * Callback function to provide returned data. + * + * Copy data into the supplied buffer, write_callback::ptr, checking size + * limits. + * + * @returns Number of bytes placed into write_callback::ptr. 0 for EOF. + *****************************************************************************/ +size_t evel_write_callback(void *contents, + size_t size, + size_t nmemb, + void *userp); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* HEARTBEAT - (includes common header, too) */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * Create a new heartbeat event. + * + * @note that the heartbeat is just a "naked" commonEventHeader! + * + * @returns pointer to the newly manufactured ::EVENT_HEADER. If the event is + * not used it must be released using ::evel_free_event + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_HEADER * evel_new_heartbeat(void); + +/**************************************************************************//** + * Free an event header. + * + * Free off the event header supplied. Will free all the contained allocated + * memory. + * + * @note It does not free the header itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_header(EVENT_HEADER * const event); + +/**************************************************************************//** + * Initialize a newly created event header. + * + * @param header Pointer to the header being initialized. + *****************************************************************************/ +void evel_init_header(EVENT_HEADER * const header); + +/**************************************************************************//** + * Set the Event Type property of the event header. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_header_type_set(EVENT_HEADER * const header, + const char * const type); + +/**************************************************************************//** + * Set the Start Epoch property of the event header. + * + * @note The Start Epoch defaults to the time of event creation. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param start_epoch_microsec + * The start epoch to set, in microseconds. + *****************************************************************************/ +void evel_start_epoch_set(EVENT_HEADER * const header, + const unsigned long long start_epoch_microsec); + +/**************************************************************************//** + * Set the Last Epoch property of the event header. + * + * @note The Last Epoch defaults to the time of event creation. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param last_epoch_microsec + * The last epoch to set, in microseconds. + *****************************************************************************/ +void evel_last_epoch_set(EVENT_HEADER * const header, + const unsigned long long last_epoch_microsec); + +/**************************************************************************//** + * Set the Reporting Entity Name property of the event header. + * + * @note The Reporting Entity Name defaults to the OpenStack VM Name. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param entity_name The entity name to set. + *****************************************************************************/ +void evel_reporting_entity_name_set(EVENT_HEADER * const header, + const char * const entity_name); + +/**************************************************************************//** + * Set the Reporting Entity Id property of the event header. + * + * @note The Reporting Entity Id defaults to the OpenStack VM UUID. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param entity_id The entity id to set. + *****************************************************************************/ +void evel_reporting_entity_id_set(EVENT_HEADER * const header, + const char * const entity_id); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* FAULT */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * Create a new fault event. + * + * + * @returns pointer to the newly manufactured ::EVENT_FAULT. If the event is + * not used it must be released using ::evel_free_fault + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_FAULT * evel_new_fault(const char * const condition, + const char * const specific_problem, + EVEL_EVENT_PRIORITIES priority, + EVEL_SEVERITIES severity); + +/**************************************************************************//** + * Free a Fault. + * + * Free off the Fault supplied. Will free all the contained allocated memory. + * + * @note It does not free the Fault itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_fault(EVENT_FAULT * event); + + +/**************************************************************************//** + * Set the Alarm Interface A property of the Fault. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param fault Pointer to the fault. + * @param interface The Alarm Interface A to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_fault_interface_set(EVENT_FAULT * fault, + const char * const interface); + +/**************************************************************************//** + * Add an additional value name/value pair to the Fault. + * + * The name and value are null delimited ASCII strings. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param fault Pointer to the fault. + * @param name ASCIIZ string with the attribute's name. + * @param value ASCIIZ string with the attribute's value. + *****************************************************************************/ +void evel_fault_addl_info_add(EVENT_FAULT * fault, char * name, char * value); + +/**************************************************************************//** + * Set the Event Type property of the Fault. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param fault Pointer to the fault. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_fault_type_set(EVENT_FAULT * fault, const char * const type); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* MEASUREMENT */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * Create a new Measurement event. + * + * @note The mandatory fields on the Measurement must be supplied to this + * factory function and are immutable once set. Optional fields have + * explicit setter functions, but again values may only be set once so + * that the Measurement has immutable properties. + * + * @param measurement_interval + * + * @returns pointer to the newly manufactured ::EVENT_MEASUREMENT. If the + * event is not used (i.e. posted) it must be released using + * ::evel_free_event. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_MEASUREMENT * evel_new_measurement(double measurement_interval); + +/**************************************************************************//** + * Free a Measurement. + * + * Free off the Measurement supplied. Will free all the contained allocated + * memory. + * + * @note It does not free the Measurement itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_measurement(EVENT_MEASUREMENT * event); + +/**************************************************************************//** + * Set the Event Type property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_measurement_type_set(EVENT_MEASUREMENT * measurement, + const char * const type); + +/**************************************************************************//** + * Set the Concurrent Sessions property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param concurrent_sessions The Concurrent Sessions to be set. + *****************************************************************************/ +void evel_measurement_conc_sess_set(EVENT_MEASUREMENT * measurement, + int concurrent_sessions); + +/**************************************************************************//** + * Set the Configured Entities property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param configured_entities The Configured Entities to be set. + *****************************************************************************/ +void evel_measurement_cfg_ents_set(EVENT_MEASUREMENT * measurement, + int configured_entities); + +/**************************************************************************//** + * Add an additional set of Errors to the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the measurement. + * @param receive_discards The number of receive discards. + * @param receive_errors The number of receive errors. + * @param transmit_discards The number of transmit discards. + * @param transmit_errors The number of transmit errors. + *****************************************************************************/ +void evel_measurement_errors_set(EVENT_MEASUREMENT * measurement, + int receive_discards, + int receive_errors, + int transmit_discards, + int transmit_errors); + +/**************************************************************************//** + * Set the Mean Request Latency property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param mean_request_latency The Mean Request Latency to be set. + *****************************************************************************/ +void evel_measurement_mean_req_lat_set(EVENT_MEASUREMENT * measurement, + double mean_request_latency); + +/**************************************************************************//** + * Set the Memory Configured property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param memory_configured The Memory Configured to be set. + *****************************************************************************/ +void evel_measurement_mem_cfg_set(EVENT_MEASUREMENT * measurement, + double memory_configured); + +/**************************************************************************//** + * Set the Memory Used property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param memory_used The Memory Used to be set. + *****************************************************************************/ +void evel_measurement_mem_used_set(EVENT_MEASUREMENT * measurement, + double memory_used); + +/**************************************************************************//** + * Set the Request Rate property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param request_rate The Request Rate to be set. + *****************************************************************************/ +void evel_measurement_request_rate_set(EVENT_MEASUREMENT * measurement, + int request_rate); + +/**************************************************************************//** + * Add an additional CPU usage value name/value pair to the Measurement. + * + * The name and value are null delimited ASCII strings. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param measurement Pointer to the measurement. + * @param id ASCIIZ string with the CPU's identifier. + * @param usage CPU utilization. + *****************************************************************************/ +void evel_measurement_cpu_use_add(EVENT_MEASUREMENT * measurement, + char * id, double usage); + +/**************************************************************************//** + * Add an additional File System usage value name/value pair to the + * Measurement. + * + * The filesystem_name is null delimited ASCII string. The library takes a + * copy so the caller does not have to preserve values after the function + * returns. + * + * @param measurement Pointer to the measurement. + * @param filesystem_name ASCIIZ string with the file-system's UUID. + * @param block_configured Block storage configured. + * @param block_used Block storage in use. + * @param block_iops Block storage IOPS. + * @param ephemeral_configured Ephemeral storage configured. + * @param ephemeral_used Ephemeral storage in use. + * @param ephemeral_iops Ephemeral storage IOPS. + *****************************************************************************/ +void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement, + char * filesystem_name, + double block_configured, + double block_used, + int block_iops, + double ephemeral_configured, + double ephemeral_used, + int ephemeral_iops); + +/**************************************************************************//** + * Add a Feature usage value name/value pair to the Measurement. + * + * The name is null delimited ASCII string. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param measurement Pointer to the measurement. + * @param feature ASCIIZ string with the feature's name. + * @param utilization Utilization of the feature. + *****************************************************************************/ +void evel_measurement_feature_use_add(EVENT_MEASUREMENT * measurement, + char * feature, + int utilization); + +/**************************************************************************//** + * Add a Additional Measurement value name/value pair to the Measurement. + * + * The name is null delimited ASCII string. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param measurement Pointer to the Measurement. + * @param group ASCIIZ string with the measurement group's name. + * @param name ASCIIZ string containing the measurement's name. + * @param name ASCIIZ string containing the measurement's value. + *****************************************************************************/ +void evel_measurement_custom_measurement_add(EVENT_MEASUREMENT * measurement, + const char * const group, + const char * const name, + const char * const value); + +/**************************************************************************//** + * Add a Codec usage value name/value pair to the Measurement. + * + * The name is null delimited ASCII string. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param measurement Pointer to the measurement. + * @param codec ASCIIZ string with the codec's name. + * @param utilization Utilization of the feature. + *****************************************************************************/ +void evel_measurement_codec_use_add(EVENT_MEASUREMENT * measurement, + char * codec, + int utilization); + +/**************************************************************************//** +} + * Set the Aggregate CPU Use property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the measurement. + * @param cpu_use The CPU use to set. + *****************************************************************************/ +void evel_measurement_agg_cpu_use_set(EVENT_MEASUREMENT * measurement, + double cpu_use); + +/**************************************************************************//** + * Set the Media Ports in Use property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the measurement. + * @param media_ports_in_use The media port usage to set. + *****************************************************************************/ +void evel_measurement_media_port_use_set(EVENT_MEASUREMENT * measurement, + int media_ports_in_use); + +/**************************************************************************//** + * Set the VNFC Scaling Metric property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the measurement. + * @param scaling_metric The scaling metric to set. + *****************************************************************************/ +void evel_measurement_vnfc_scaling_metric_set(EVENT_MEASUREMENT * measurement, + double scaling_metric); + +/**************************************************************************//** + * Create a new Latency Bucket to be added to a Measurement event. + * + * @note The mandatory fields on the ::MEASUREMENT_LATENCY_BUCKET must be + * supplied to this factory function and are immutable once set. + * Optional fields have explicit setter functions, but again values + * may only be set once so that the ::MEASUREMENT_LATENCY_BUCKET has + * immutable properties. + * + * @param count Count of events in this bucket. + * + * @returns pointer to the newly manufactured ::MEASUREMENT_LATENCY_BUCKET. + * @retval NULL Failed to create the Latency Bucket. + *****************************************************************************/ +MEASUREMENT_LATENCY_BUCKET * evel_new_meas_latency_bucket(const int count); + +/**************************************************************************//** + * Set the High End property of the Measurement Latency Bucket. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param bucket Pointer to the Measurement Latency Bucket. + * @param high_end High end of the bucket's range. + *****************************************************************************/ +void evel_meas_latency_bucket_high_end_set( + MEASUREMENT_LATENCY_BUCKET * const bucket, + const double high_end); + +/**************************************************************************//** + * Set the Low End property of the Measurement Latency Bucket. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param bucket Pointer to the Measurement Latency Bucket. + * @param low_end Low end of the bucket's range. + *****************************************************************************/ +void evel_meas_latency_bucket_low_end_set( + MEASUREMENT_LATENCY_BUCKET * const bucket, + const double low_end); + +/**************************************************************************//** + * Add an additional Measurement Latency Bucket to the specified event. + * + * @param measurement Pointer to the Measurement event. + * @param bucket Pointer to the Measurement Latency Bucket to add. + *****************************************************************************/ +void evel_meas_latency_bucket_add(EVENT_MEASUREMENT * const measurement, + MEASUREMENT_LATENCY_BUCKET * const bucket); + +/**************************************************************************//** + * Add an additional Latency Distribution bucket to the Measurement. + * + * This function implements the previous API, purely for convenience. + * + * @param measurement Pointer to the measurement. + * @param low_end Low end of the bucket's range. + * @param high_end High end of the bucket's range. + * @param count Count of events in this bucket. + *****************************************************************************/ +void evel_measurement_latency_add(EVENT_MEASUREMENT * const measurement, + const double low_end, + const double high_end, + const int count); + +/**************************************************************************//** + * Create a new vNIC Use to be added to a Measurement event. + * + * @note The mandatory fields on the ::MEASUREMENT_VNIC_USE must be supplied + * to this factory function and are immutable once set. Optional + * fields have explicit setter functions, but again values may only be + * set once so that the ::MEASUREMENT_VNIC_USE has immutable + * properties. + * + * @param vnic_id ASCIIZ string with the vNIC's ID. + * @param packets_in Total packets received. + * @param packets_out Total packets transmitted. + * @param bytes_in Total bytes received. + * @param bytes_out Total bytes transmitted. + * + * @returns pointer to the newly manufactured ::MEASUREMENT_VNIC_USE. + * If the structure is not used it must be released using + * ::evel_free_measurement_vnic_use. + * @retval NULL Failed to create the vNIC Use. + *****************************************************************************/ +MEASUREMENT_VNIC_USE * evel_new_measurement_vnic_use(char * const vnic_id, + const int packets_in, + const int packets_out, + const int bytes_in, + const int bytes_out); + +/**************************************************************************//** + * Free a vNIC Use. + * + * Free off the ::MEASUREMENT_VNIC_USE supplied. Will free all the contained + * allocated memory. + * + * @note It does not free the vNIC Use itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_measurement_vnic_use(MEASUREMENT_VNIC_USE * const vnic_use); + +/**************************************************************************//** + * Set the Broadcast Packets Received property of the vNIC Use. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param vnic_use Pointer to the vNIC Use. + * @param broadcast_packets_in + * Broadcast packets received. + *****************************************************************************/ +void evel_vnic_use_bcast_pkt_in_set(MEASUREMENT_VNIC_USE * const vnic_use, + const int broadcast_packets_in); + +/**************************************************************************//** + * Set the Broadcast Packets Transmitted property of the vNIC Use. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param vnic_use Pointer to the vNIC Use. + * @param broadcast_packets_out + * Broadcast packets transmitted. + *****************************************************************************/ +void evel_vnic_use_bcast_pkt_out_set(MEASUREMENT_VNIC_USE * const vnic_use, + const int broadcast_packets_out); + +/**************************************************************************//** + * Set the Multicast Packets Received property of the vNIC Use. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param vnic_use Pointer to the vNIC Use. + * @param multicast_packets_in + * Multicast packets received. + *****************************************************************************/ +void evel_vnic_use_mcast_pkt_in_set(MEASUREMENT_VNIC_USE * const vnic_use, + const int multicast_packets_in); + +/**************************************************************************//** + * Set the Multicast Packets Transmitted property of the vNIC Use. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param vnic_use Pointer to the vNIC Use. + * @param multicast_packets_out + * Multicast packets transmitted. + *****************************************************************************/ +void evel_vnic_use_mcast_pkt_out_set(MEASUREMENT_VNIC_USE * const vnic_use, + const int multicast_packets_out); + +/**************************************************************************//** + * Set the Unicast Packets Received property of the vNIC Use. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param vnic_use Pointer to the vNIC Use. + * @param unicast_packets_in + * Unicast packets received. + *****************************************************************************/ +void evel_vnic_use_ucast_pkt_in_set(MEASUREMENT_VNIC_USE * const vnic_use, + const int unicast_packets_in); + +/**************************************************************************//** + * Set the Unicast Packets Transmitted property of the vNIC Use. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param vnic_use Pointer to the vNIC Use. + * @param unicast_packets_out + * Unicast packets transmitted. + *****************************************************************************/ +void evel_vnic_use_ucast_pkt_out_set(MEASUREMENT_VNIC_USE * const vnic_use, + const int unicast_packets_out); + +/**************************************************************************//** + * Add an additional vNIC Use to the specified Measurement event. + * + * @param measurement Pointer to the measurement. + * @param vnic_use Pointer to the vNIC Use to add. + *****************************************************************************/ +void evel_meas_vnic_use_add(EVENT_MEASUREMENT * const measurement, + MEASUREMENT_VNIC_USE * const vnic_use); + +/**************************************************************************//** + * Add an additional vNIC usage record Measurement. + * + * This function implements the previous API, purely for convenience. + * + * The ID is null delimited ASCII string. The library takes a copy so the + * caller does not have to preserve values after the function returns. + * + * @param measurement Pointer to the measurement. + * @param vnic_id ASCIIZ string with the vNIC's ID. + * @param packets_in Total packets received. + * @param packets_out Total packets transmitted. + * @param broadcast_packets_in Broadcast packets received. + * @param broadcast_packets_out Broadcast packets transmitted. + * @param bytes_in Total bytes received. + * @param bytes_out Total bytes transmitted. + * @param multicast_packets_in Multicast packets received. + * @param multicast_packets_out Multicast packets transmitted. + * @param unicast_packets_in Unicast packets received. + * @param unicast_packets_out Unicast packets transmitted. + *****************************************************************************/ +void evel_measurement_vnic_use_add(EVENT_MEASUREMENT * const measurement, + char * const vnic_id, + const int packets_in, + const int packets_out, + const int broadcast_packets_in, + const int broadcast_packets_out, + const int bytes_in, + const int bytes_out, + const int multicast_packets_in, + const int multicast_packets_out, + const int unicast_packets_in, + const int unicast_packets_out); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* REPORT */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * Create a new Report event. + * + * @note The mandatory fields on the Report must be supplied to this + * factory function and are immutable once set. Optional fields have + * explicit setter functions, but again values may only be set once so + * that the Report has immutable properties. + * + * @param measurement_interval + * + * @returns pointer to the newly manufactured ::EVENT_REPORT. If the event is + * not used (i.e. posted) it must be released using + * ::evel_free_report. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_REPORT * evel_new_report(double measurement_interval); + +/**************************************************************************//** + * Free a Report. + * + * Free off the Report supplied. Will free all the contained allocated memory. + * + * @note It does not free the Report itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_report(EVENT_REPORT * event); + +/**************************************************************************//** + * Set the Event Type property of the Report. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param report Pointer to the Report. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_report_type_set(EVENT_REPORT * report, const char * const type); + +/**************************************************************************//** + * Add a Feature usage value name/value pair to the Report. + * + * The name is null delimited ASCII string. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param report Pointer to the report. + * @param feature ASCIIZ string with the feature's name. + * @param utilization Utilization of the feature. + *****************************************************************************/ +void evel_report_feature_use_add(EVENT_REPORT * report, + char * feature, + int utilization); + +/**************************************************************************//** + * Add a Additional Measurement value name/value pair to the Report. + * + * The name is null delimited ASCII string. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param report Pointer to the report. + * @param group ASCIIZ string with the measurement group's name. + * @param name ASCIIZ string containing the measurement's name. + * @param value ASCIIZ string containing the measurement's value. + *****************************************************************************/ +void evel_report_custom_measurement_add(EVENT_REPORT * report, + const char * const group, + const char * const name, + const char * const value); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* MOBILE_FLOW */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * Create a new Mobile Flow event. + * + * @note The mandatory fields on the Mobile Flow must be supplied to this + * factory function and are immutable once set. Optional fields have + * explicit setter functions, but again values may only be set once so + * that the Mobile Flow has immutable properties. + * + * @param flow_direction + * @param gtp_per_flow_metrics + * @param ip_protocol_type + * @param ip_version + * @param other_endpoint_ip_address + * @param other_endpoint_port + * @param reporting_endpoint_ip_addr + * @param reporting_endpoint_port + * + * @returns pointer to the newly manufactured ::EVENT_MOBILE_FLOW. If the + * event is not used (i.e. posted) it must be released using + * ::evel_free_mobile_flow. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_MOBILE_FLOW * evel_new_mobile_flow( + const char * const flow_direction, + MOBILE_GTP_PER_FLOW_METRICS * gtp_per_flow_metrics, + const char * const ip_protocol_type, + const char * const ip_version, + const char * const other_endpoint_ip_address, + int other_endpoint_port, + const char * const reporting_endpoint_ip_addr, + int reporting_endpoint_port); + +/**************************************************************************//** + * Free a Mobile Flow. + * + * Free off the Mobile Flow supplied. Will free all the contained allocated + * memory. + * + * @note It does not free the Mobile Flow itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_mobile_flow(EVENT_MOBILE_FLOW * event); + +/**************************************************************************//** + * Set the Event Type property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_mobile_flow_type_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const type); + +/**************************************************************************//** + * Set the Application Type property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param type The Application Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_mobile_flow_app_type_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const type); + +/**************************************************************************//** + * Set the Application Protocol Type property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param type The Application Protocol Type to be set. ASCIIZ string. + * The caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_flow_app_prot_type_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const type); + +/**************************************************************************//** + * Set the Application Protocol Version property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param version The Application Protocol Version to be set. ASCIIZ + * string. The caller does not need to preserve the value + * once the function returns. + *****************************************************************************/ +void evel_mobile_flow_app_prot_ver_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const version); + +/**************************************************************************//** + * Set the CID property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param cid The CID to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_cid_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const cid); + +/**************************************************************************//** + * Set the Connection Type property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param type The Connection Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_mobile_flow_con_type_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const type); + +/**************************************************************************//** + * Set the ECGI property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param ecgi The ECGI to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_ecgi_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const ecgi); + +/**************************************************************************//** + * Set the GTP Protocol Type property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param type The GTP Protocol Type to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_flow_gtp_prot_type_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const type); + +/**************************************************************************//** + * Set the GTP Protocol Version property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param version The GTP Protocol Version to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_flow_gtp_prot_ver_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const version); + +/**************************************************************************//** + * Set the HTTP Header property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param header The HTTP header to be set. ASCIIZ string. The caller does + * not need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_http_header_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const header); + +/**************************************************************************//** + * Set the IMEI property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param imei The IMEI to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_imei_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const imei); + +/**************************************************************************//** + * Set the IMSI property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param imsi The IMSI to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_imsi_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const imsi); + +/**************************************************************************//** + * Set the LAC property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param lac The LAC to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_lac_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const lac); + +/**************************************************************************//** + * Set the MCC property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param mcc The MCC to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_mcc_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const mcc); + +/**************************************************************************//** + * Set the MNC property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param mnc The MNC to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_mnc_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const mnc); + +/**************************************************************************//** + * Set the MSISDN property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param msisdn The MSISDN to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_msisdn_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const msisdn); + +/**************************************************************************//** + * Set the Other Functional Role property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param role The Other Functional Role to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_flow_other_func_role_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const role); + +/**************************************************************************//** + * Set the RAC property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param rac The RAC to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_rac_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const rac); + +/**************************************************************************//** + * Set the Radio Access Technology property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param tech The Radio Access Technology to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_flow_radio_acc_tech_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const tech); + +/**************************************************************************//** + * Set the SAC property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param sac The SAC to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_sac_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const sac); + +/**************************************************************************//** + * Set the Sampling Algorithm property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param algorithm The Sampling Algorithm to be set. + *****************************************************************************/ +void evel_mobile_flow_samp_alg_set(EVENT_MOBILE_FLOW * mobile_flow, + int algorithm); + +/**************************************************************************//** + * Set the TAC property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param tac The TAC to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_tac_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const tac); + +/**************************************************************************//** + * Set the Tunnel ID property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param tunnel_id The Tunnel ID to be set. ASCIIZ string. The caller does + * not need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_tunnel_id_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const tunnel_id); + +/**************************************************************************//** + * Set the VLAN ID property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param vlan_id The VLAN ID to be set. ASCIIZ string. The caller does + * not need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_vlan_id_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const vlan_id); + +/**************************************************************************//** + * Create a new Mobile GTP Per Flow Metrics. + * + * @note The mandatory fields on the Mobile GTP Per Flow Metrics must be + * supplied to this factory function and are immutable once set. + * Optional fields have explicit setter functions, but again values + * may only be set once so that the Mobile GTP Per Flow Metrics has + * immutable properties. + * + * @param avg_bit_error_rate + * @param avg_packet_delay_variation + * @param avg_packet_latency + * @param avg_receive_throughput + * @param avg_transmit_throughput + * @param flow_activation_epoch + * @param flow_activation_microsec + * @param flow_deactivation_epoch + * @param flow_deactivation_microsec + * @param flow_deactivation_time + * @param flow_status + * @param max_packet_delay_variation + * @param num_activation_failures + * @param num_bit_errors + * @param num_bytes_received + * @param num_bytes_transmitted + * @param num_dropped_packets + * @param num_l7_bytes_received + * @param num_l7_bytes_transmitted + * @param num_lost_packets + * @param num_out_of_order_packets + * @param num_packet_errors + * @param num_packets_received_excl_retrans + * @param num_packets_received_incl_retrans + * @param num_packets_transmitted_incl_retrans + * @param num_retries + * @param num_timeouts + * @param num_tunneled_l7_bytes_received + * @param round_trip_time + * @param time_to_first_byte + * + * @returns pointer to the newly manufactured ::MOBILE_GTP_PER_FLOW_METRICS. + * If the structure is not used it must be released using + * ::evel_free_mobile_gtp_flow_metrics. + * @retval NULL Failed to create the event. + *****************************************************************************/ +MOBILE_GTP_PER_FLOW_METRICS * evel_new_mobile_gtp_flow_metrics( + double avg_bit_error_rate, + double avg_packet_delay_variation, + int avg_packet_latency, + int avg_receive_throughput, + int avg_transmit_throughput, + int flow_activation_epoch, + int flow_activation_microsec, + int flow_deactivation_epoch, + int flow_deactivation_microsec, + time_t flow_deactivation_time, + const char * const flow_status, + int max_packet_delay_variation, + int num_activation_failures, + int num_bit_errors, + int num_bytes_received, + int num_bytes_transmitted, + int num_dropped_packets, + int num_l7_bytes_received, + int num_l7_bytes_transmitted, + int num_lost_packets, + int num_out_of_order_packets, + int num_packet_errors, + int num_packets_received_excl_retrans, + int num_packets_received_incl_retrans, + int num_packets_transmitted_incl_retrans, + int num_retries, + int num_timeouts, + int num_tunneled_l7_bytes_received, + int round_trip_time, + int time_to_first_byte); + +/**************************************************************************//** + * Free a Mobile GTP Per Flow Metrics. + * + * Free off the Mobile GTP Per Flow Metrics supplied. Will free all the + * contained allocated memory. + * + * @note It does not free the Mobile GTP Per Flow Metrics itself, since that + * may be part of a larger structure. + *****************************************************************************/ +void evel_free_mobile_gtp_flow_metrics(MOBILE_GTP_PER_FLOW_METRICS * metrics); + +/**************************************************************************//** + * Set the Duration of Connection Failed Status property of the Mobile GTP Per + * Flow Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param duration The Duration of Connection Failed Status to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_dur_con_fail_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int duration); + +/**************************************************************************//** + * Set the Duration of Tunnel Failed Status property of the Mobile GTP Per Flow + * Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param duration The Duration of Tunnel Failed Status to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_dur_tun_fail_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int duration); + +/**************************************************************************//** + * Set the Activated By property of the Mobile GTP Per Flow metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param act_by The Activated By to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_mobile_gtp_metrics_act_by_set(MOBILE_GTP_PER_FLOW_METRICS * metrics, + const char * const act_by); + +/**************************************************************************//** + * Set the Activation Time property of the Mobile GTP Per Flow metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param act_time The Activation Time to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_mobile_gtp_metrics_act_time_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + time_t act_time); + +/**************************************************************************//** + * Set the Deactivated By property of the Mobile GTP Per Flow metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param deact_by The Deactivated By to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_mobile_gtp_metrics_deact_by_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + const char * const deact_by); + +/**************************************************************************//** + * Set the GTP Connection Status property of the Mobile GTP Per Flow metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param status The GTP Connection Status to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_gtp_metrics_con_status_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + const char * const status); + +/**************************************************************************//** + * Set the GTP Tunnel Status property of the Mobile GTP Per Flow metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param status The GTP Tunnel Status to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_gtp_metrics_tun_status_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + const char * const status); + +/**************************************************************************//** + * Set an IP Type-of-Service count property of the Mobile GTP Per Flow metrics. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param index The index of the IP Type-of-Service. + * @param count The count. + *****************************************************************************/ +void evel_mobile_gtp_metrics_iptos_set(MOBILE_GTP_PER_FLOW_METRICS * metrics, + int index, + int count); + +/**************************************************************************//** + * Set the Large Packet Round-Trip Time property of the Mobile GTP Per Flow + * Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param rtt The Large Packet Round-Trip Time to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_large_pkt_rtt_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int rtt); + +/**************************************************************************//** + * Set the Large Packet Threshold property of the Mobile GTP Per Flow Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param threshold The Large Packet Threshold to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_large_pkt_thresh_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + double threshold); + +/**************************************************************************//** + * Set the Max Receive Bit Rate property of the Mobile GTP Per Flow Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param rate The Max Receive Bit Rate to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_max_rcv_bit_rate_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int rate); + +/**************************************************************************//** + * Set the Max Transmit Bit Rate property of the Mobile GTP Per Flow Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param rate The Max Transmit Bit Rate to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_max_trx_bit_rate_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int rate); + +/**************************************************************************//** + * Set the Number of GTP Echo Failures property of the Mobile GTP Per Flow + * Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param num The Number of GTP Echo Failures to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_num_echo_fail_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int num); + +/**************************************************************************//** + * Set the Number of GTP Tunnel Errors property of the Mobile GTP Per Flow + * Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param num The Number of GTP Tunnel Errors to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_num_tun_fail_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int num); + +/**************************************************************************//** + * Set the Number of HTTP Errors property of the Mobile GTP Per Flow Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param num The Number of HTTP Errors to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_num_http_errors_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int num); + +/**************************************************************************//** + * Add a TCP flag count to the metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param tcp_flag The TCP flag count to be updated. + * @param count The associated flag count. + *****************************************************************************/ +void evel_mobile_gtp_metrics_tcp_flag_count_add( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + const EVEL_TCP_FLAGS tcp_flag, + const int count); + +/**************************************************************************//** + * Add a QCI COS count to the metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param qci_cos The QCI COS count to be updated. + * @param count The associated QCI COS count. + *****************************************************************************/ +void evel_mobile_gtp_metrics_qci_cos_count_add( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + const EVEL_QCI_COS_TYPES qci_cos, + const int count); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* SERVICE EVENTS */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * Create a new Service event. + * + * @note The mandatory fields on the Service must be supplied to + * this factory function and are immutable once set. Optional fields + * have explicit setter functions, but again values may only be set + * once so that the event has immutable properties. + * @param vendor_id The vendor id to encode in the event instance id. + * @param event_id The vendor event id to encode in the event instance id. + * @returns pointer to the newly manufactured ::EVENT_SERVICE. If the event + * is not used (i.e. posted) it must be released using + * ::evel_free_service. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_SERVICE * evel_new_service(const char * const vendor_id, + const char * const event_id); + +/**************************************************************************//** + * Free a Service Events event. + * + * Free off the event supplied. Will free all the contained allocated memory. + * + * @note It does not free the event itself, since that may be part of a larger + * structure. + *****************************************************************************/ +void evel_free_service(EVENT_SERVICE * const event); + +/**************************************************************************//** + * Set the Event Type property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_service_type_set(EVENT_SERVICE * const event, + const char * const type); + +/**************************************************************************//** + * Set the Product Id property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param product_id The vendor product id to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_service_product_id_set(EVENT_SERVICE * const event, + const char * const product_id); + +/**************************************************************************//** + * Set the Subsystem Id property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param subsystem_id The vendor subsystem id to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_service_subsystem_id_set(EVENT_SERVICE * const event, + const char * const subsystem_id); + +/**************************************************************************//** + * Set the Friendly Name property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param friendly_name The vendor friendly name to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_service_friendly_name_set(EVENT_SERVICE * const event, + const char * const friendly_name); + +/**************************************************************************//** + * Set the correlator property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param correlator The correlator to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_service_correlator_set(EVENT_SERVICE * const event, + const char * const correlator); + +/**************************************************************************//** + * Set the Codec property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param codec The codec to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_service_codec_set(EVENT_SERVICE * const event, + const char * const codec); + +/**************************************************************************//** + * Set the Callee Side Codec property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param codec The codec to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_service_callee_codec_set(EVENT_SERVICE * const event, + const char * const codec); + +/**************************************************************************//** + * Set the Caller Side Codec property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param codec The codec to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_service_caller_codec_set(EVENT_SERVICE * const event, + const char * const codec); + +/**************************************************************************//** + * Set the RTCP Data property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtcp_data The RTCP Data to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_service_rtcp_data_set(EVENT_SERVICE * const event, + const char * const rtcp_data); + +/**************************************************************************//** + * Set the Adjacency Name property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param adjacency_name + * The adjacency name to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_service_adjacency_name_set(EVENT_SERVICE * const event, + const char * const adjacency_name); + +/**************************************************************************//** + * Set the Endpoint Descriptor property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param endpoint_desc The endpoint descriptor to be set. + *****************************************************************************/ +void evel_service_endpoint_desc_set( + EVENT_SERVICE * const event, + const EVEL_SERVICE_ENDPOINT_DESC endpoint_desc); + +/**************************************************************************//** + * Set the Endpoint Jitter property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param jitter The jitter to be set. + *****************************************************************************/ +void evel_service_endpoint_jitter_set(EVENT_SERVICE * const event, + const int jitter); + +/**************************************************************************//** + * Set the Endpoint Rtp Octets Discarded property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_oct_disc The discard count. + *****************************************************************************/ +void evel_service_endpoint_rtp_oct_disc_set(EVENT_SERVICE * const event, + const int rtp_oct_disc); + +/**************************************************************************//** + * Set the Endpoint Rtp Octets Received property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_oct_recv The receive count. + *****************************************************************************/ +void evel_service_endpoint_rtp_oct_recv_set(EVENT_SERVICE * const event, + const int rtp_oct_recv); + +/**************************************************************************//** + * Set the Endpoint Rtp Octets Sent property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_oct_sent The send count. + *****************************************************************************/ +void evel_service_endpoint_rtp_oct_sent_set(EVENT_SERVICE * const event, + const int rtp_oct_sent); + +/**************************************************************************//** + * Set the Endpoint Rtp Packets Discarded property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_pkt_disc The discard count. + *****************************************************************************/ +void evel_service_endpoint_rtp_pkt_disc_set(EVENT_SERVICE * const event, + const int rtp_pkt_disc); + +/**************************************************************************//** + * Set the Endpoint Rtp Packets Received property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_pkt_recv The receive count. + *****************************************************************************/ +void evel_service_endpoint_rtp_pkt_recv_set(EVENT_SERVICE * const event, + const int rtp_pkt_recv); + +/**************************************************************************//** + * Set the Endpoint Rtp Packets Sent property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_pkt_sent The send count. + *****************************************************************************/ +void evel_service_endpoint_rtp_pkt_sent_set(EVENT_SERVICE * const event, + const int rtp_pkt_sent); + +/**************************************************************************//** + * Set the Local Jitter property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param jitter The jitter to be set. + *****************************************************************************/ +void evel_service_local_jitter_set(EVENT_SERVICE * const event, + const int jitter); + +/**************************************************************************//** + * Set the Local Rtp Octets Discarded property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_oct_disc The discard count. + *****************************************************************************/ +void evel_service_local_rtp_oct_disc_set(EVENT_SERVICE * const event, + const int rtp_oct_disc); + +/**************************************************************************//** + * Set the Local Rtp Octets Received property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_oct_recv The receive count. + *****************************************************************************/ +void evel_service_local_rtp_oct_recv_set(EVENT_SERVICE * const event, + const int rtp_oct_recv); + +/**************************************************************************//** + * Set the Local Rtp Octets Sent property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_oct_sent The send count. + *****************************************************************************/ +void evel_service_local_rtp_oct_sent_set(EVENT_SERVICE * const event, + const int rtp_oct_sent); + +/**************************************************************************//** + * Set the Local Rtp Packets Discarded property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_pkt_disc The discard count. + *****************************************************************************/ +void evel_service_local_rtp_pkt_disc_set(EVENT_SERVICE * const event, + const int rtp_pkt_disc); + +/**************************************************************************//** + * Set the Local Rtp Packets Received property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_pkt_recv The receive count. + *****************************************************************************/ +void evel_service_local_rtp_pkt_recv_set(EVENT_SERVICE * const event, + const int rtp_pkt_recv); + +/**************************************************************************//** + * Set the Local Rtp Packets Sent property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_pkt_sent The send count. + *****************************************************************************/ +void evel_service_local_rtp_pkt_sent_set(EVENT_SERVICE * const event, + const int rtp_pkt_sent); + +/**************************************************************************//** + * Set the Mos Cqe property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param mos_cqe The mosCqe to be set. + *****************************************************************************/ +void evel_service_mos_cqe_set(EVENT_SERVICE * const event, + const double mos_cqe); + +/**************************************************************************//** + * Set the Packets Lost property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param packets_lost The number of packets lost to be set. + *****************************************************************************/ +void evel_service_packets_lost_set(EVENT_SERVICE * const event, + const int packets_lost); + +/**************************************************************************//** + * Set the packet Loss Percent property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param packet_loss_percent + * The packet loss in percent. + *****************************************************************************/ +void evel_service_packet_loss_percent_set(EVENT_SERVICE * const event, + const double packet_loss_percent); + +/**************************************************************************//** + * Set the R Factor property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param r_factor The R Factor to be set. + *****************************************************************************/ +void evel_service_r_factor_set(EVENT_SERVICE * const event, + const int r_factor); + +/**************************************************************************//** + * Set the Round Trip Delay property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param round_trip_delay + * The Round trip delay to be set. + *****************************************************************************/ +void evel_service_round_trip_delay_set(EVENT_SERVICE * const event, + const int round_trip_delay); + +/**************************************************************************//** + * Set the Phone Number property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param phone_number The Phone Number to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_service_phone_number_set(EVENT_SERVICE * const event, + const char * const phone_number); + +/**************************************************************************//** + * Add a name/value pair to the Service, under the additionalFields array. + * + * The name and value are null delimited ASCII strings. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param event Pointer to the Service event. + * @param name ASCIIZ string with the field's name. The caller does not + * need to preserve the value once the function returns. + * @param value ASCIIZ string with the field's value. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_service_addl_field_add(EVENT_SERVICE * const event, + const char * const name, + const char * const value); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* SIGNALING */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * Create a new Signaling event. + * + * @note The mandatory fields on the Signaling must be supplied to + * this factory function and are immutable once set. Optional fields + * have explicit setter functions, but again values may only be set + * once so that the event has immutable properties. + * @param vendor_id The vendor id to encode in the event instance id. + * @param event_id The vendor event id to encode in the event instance id. + * @returns pointer to the newly manufactured ::EVENT_SIGNALING. If the event + * is not used (i.e. posted) it must be released using + * ::evel_free_signaling. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_SIGNALING * evel_new_signaling(const char * const vendor_id, + const char * const event_id); + +/**************************************************************************//** + * Free a Signaling event. + * + * Free off the event supplied. Will free all the contained allocated memory. + * + * @note It does not free the event itself, since that may be part of a larger + * structure. + *****************************************************************************/ +void evel_free_signaling(EVENT_SIGNALING * const event); + +/**************************************************************************//** + * Set the Event Type property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_type_set(EVENT_SIGNALING * const event, + const char * const type); + +/**************************************************************************//** + * Set the Product Id property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param product_id The vendor product id to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_signaling_product_id_set(EVENT_SIGNALING * const event, + const char * const product_id); + +/**************************************************************************//** + * Set the Subsystem Id property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param subsystem_id The vendor subsystem id to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_signaling_subsystem_id_set(EVENT_SIGNALING * const event, + const char * const subsystem_id); + +/**************************************************************************//** + * Set the Friendly Name property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param friendly_name The vendor friendly name to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_signaling_friendly_name_set(EVENT_SIGNALING * const event, + const char * const friendly_name); + +/**************************************************************************//** + * Set the Correlator property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param correlator The correlator to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_correlator_set(EVENT_SIGNALING * const event, + const char * const correlator); + +/**************************************************************************//** + * Set the Local Ip Address property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param local_ip_address + * The Local Ip Address to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_signaling_local_ip_address_set(EVENT_SIGNALING * const event, + const char * const local_ip_address); + +/**************************************************************************//** + * Set the Local Port property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param local_port The Local Port to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_local_port_set(EVENT_SIGNALING * const event, + const char * const local_port); + +/**************************************************************************//** + * Set the Remote Ip Address property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param remote_ip_address + * The Remote Ip Address to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_signaling_remote_ip_address_set(EVENT_SIGNALING * const event, + const char * const remote_ip_address); + +/**************************************************************************//** + * Set the Remote Port property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param remote_port The Remote Port to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_remote_port_set(EVENT_SIGNALING * const event, + const char * const remote_port); + +/**************************************************************************//** + * Set the Compressed SIP property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param compressed_sip + * The Compressed SIP to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_compressed_sip_set(EVENT_SIGNALING * const event, + const char * const compressed_sip); + +/**************************************************************************//** + * Set the Summary SIP property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param summary_sip The Summary SIP to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_summary_sip_set(EVENT_SIGNALING * const event, + const char * const summary_sip); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* STATE CHANGE */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * Create a new State Change event. + * + * @note The mandatory fields on the Syslog must be supplied to this factory + * function and are immutable once set. Optional fields have explicit + * setter functions, but again values may only be set once so that the + * Syslog has immutable properties. + * + * @param new_state The new state of the reporting entity. + * @param old_state The old state of the reporting entity. + * @param interface The card or port name of the reporting entity. + * + * @returns pointer to the newly manufactured ::EVENT_STATE_CHANGE. If the + * event is not used it must be released using + * ::evel_free_state_change + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_STATE_CHANGE * evel_new_state_change(const EVEL_ENTITY_STATE new_state, + const EVEL_ENTITY_STATE old_state, + const char * const interface); + +/**************************************************************************//** + * Free a State Change. + * + * Free off the State Change supplied. Will free all the contained allocated + * memory. + * + * @note It does not free the State Change itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_state_change(EVENT_STATE_CHANGE * const state_change); + +/**************************************************************************//** + * Set the Event Type property of the State Change. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param state_change Pointer to the ::EVENT_STATE_CHANGE. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_state_change_type_set(EVENT_STATE_CHANGE * const state_change, + const char * const type); + +/**************************************************************************//** + * Add an additional field name/value pair to the State Change. + * + * The name and value are null delimited ASCII strings. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param state_change Pointer to the ::EVENT_STATE_CHANGE. + * @param name ASCIIZ string with the attribute's name. The caller + * does not need to preserve the value once the function + * returns. + * @param value ASCIIZ string with the attribute's value. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_state_change_addl_field_add(EVENT_STATE_CHANGE * const state_change, + const char * const name, + const char * const value); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* SYSLOG */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * Create a new syslog event. + * + * @note The mandatory fields on the Syslog must be supplied to this factory + * function and are immutable once set. Optional fields have explicit + * setter functions, but again values may only be set once so that the + * Syslog has immutable properties. + * + * @param event_source_type + * @param syslog_msg + * @param syslog_tag + * + * @returns pointer to the newly manufactured ::EVENT_SYSLOG. If the event is + * not used it must be released using ::evel_free_syslog + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_SYSLOG * evel_new_syslog(EVEL_SOURCE_TYPES event_source_type, + const char * const syslog_msg, + const char * const syslog_tag); + +/**************************************************************************//** + * Set the Event Type property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the syslog. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_type_set(EVENT_SYSLOG * syslog, + const char * const type); + +/**************************************************************************//** + * Free a Syslog. + * + * Free off the Syslog supplied. Will free all the contained allocated memory. + * + * @note It does not free the Syslog itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_syslog(EVENT_SYSLOG * event); + +/**************************************************************************//** + * Add an additional field name/value pair to the Syslog. + * + * The name and value are null delimited ASCII strings. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param syslog Pointer to the syslog. + * @param name ASCIIZ string with the attribute's name. The caller + * does not need to preserve the value once the function + * returns. + * @param value ASCIIZ string with the attribute's value. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_addl_field_add(EVENT_SYSLOG * syslog, + char * name, + char * value); + +/**************************************************************************//** + * Set the Event Source Host property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the Syslog. + * @param host The Event Source Host to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_syslog_event_source_host_set(EVENT_SYSLOG * syslog, + const char * const host); + +/**************************************************************************//** + * Set the Syslog Facility property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the Syslog. + * @param facility The Syslog Facility to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_facility_set(EVENT_SYSLOG * syslog, + EVEL_SYSLOG_FACILITIES facility); + +/**************************************************************************//** + * Set the Process property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the Syslog. + * @param proc The Process to be set. ASCIIZ string. The caller does + * not need to preserve the value once the function returns. + *****************************************************************************/ +void evel_syslog_proc_set(EVENT_SYSLOG * syslog, const char * const proc); + +/**************************************************************************//** + * Set the Process ID property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the Syslog. + * @param proc_id The Process ID to be set. + *****************************************************************************/ +void evel_syslog_proc_id_set(EVENT_SYSLOG * syslog, int proc_id); + +/**************************************************************************//** + * Set the Version property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the Syslog. + * @param version The Version to be set. + *****************************************************************************/ +void evel_syslog_version_set(EVENT_SYSLOG * syslog, int version); + +/**************************************************************************//** + * Set the Structured Data property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the Syslog. + * @param s_data The Structured Data to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_s_data_set(EVENT_SYSLOG * syslog, const char * const s_data); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* OTHER */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * Create a new other event. + * + * + * @returns pointer to the newly manufactured ::EVENT_OTHER. If the event is + * not used it must be released using ::evel_free_other. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_OTHER * evel_new_other(void); + +/**************************************************************************//** + * Free an Other. + * + * Free off the Other supplied. Will free all the contained allocated memory. + * + * @note It does not free the Other itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_other(EVENT_OTHER * event); + +/**************************************************************************//** + * Set the Event Type property of the Other. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param other Pointer to the Other. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_other_type_set(EVENT_OTHER * other, + const char * const type); + +/**************************************************************************//** + * Add a value name/value pair to the Other. + * + * The name and value are null delimited ASCII strings. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param other Pointer to the Other. + * @param name ASCIIZ string with the attribute's name. + * @param value ASCIIZ string with the attribute's value. + *****************************************************************************/ +void evel_other_field_add(EVENT_OTHER * other, + char * name, + char * value); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* THROTTLING */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * Return the current measurement interval provided by the Event Listener. + * + * @returns The current measurement interval + * @retval EVEL_MEASUREMENT_INTERVAL_UKNOWN (0) - interval has not been + * specified + *****************************************************************************/ +int evel_get_measurement_interval(); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* LOGGING */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Debug macros. */ +/*****************************************************************************/ +#define EVEL_DEBUG(FMT, ...) log_debug(EVEL_LOG_DEBUG, (FMT), ##__VA_ARGS__) +#define EVEL_INFO(FMT, ...) log_debug(EVEL_LOG_INFO, (FMT), ##__VA_ARGS__) +#define EVEL_SPAMMY(FMT, ...) log_debug(EVEL_LOG_SPAMMY, (FMT), ##__VA_ARGS__) +#define EVEL_ERROR(FMT, ...) log_debug(EVEL_LOG_ERROR, "ERROR: " FMT, \ + ##__VA_ARGS__) +#define EVEL_ENTER() \ + { \ + log_debug(EVEL_LOG_DEBUG, "Enter %s {", __FUNCTION__); \ + debug_indent += 2; \ + } +#define EVEL_EXIT() \ + { \ + debug_indent -= 2; \ + log_debug(EVEL_LOG_DEBUG, "Exit %s }", __FUNCTION__); \ + } + +#define INDENT_SEPARATORS \ + "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | " + +extern EVEL_LOG_LEVELS debug_level; +extern int debug_indent; +extern FILE * fout; + +#define EVEL_DEBUG_ON() ((debug_level) >= EVEL_LOG_DEBUG) + +/**************************************************************************//** + * Initialize logging + * + * @param[in] level The debugging level - one of ::EVEL_LOG_LEVELS. + * @param[in] ident The identifier for our logs. + *****************************************************************************/ +void log_initialize(EVEL_LOG_LEVELS level, const char * ident); + +/**************************************************************************//** + * Log debug information + * + * Logs debugging information in a platform independent manner. + * + * @param[in] level The debugging level - one of ::EVEL_LOG_LEVELS. + * @param[in] format Log formatting string in printf format. + * @param[in] ... Variable argument list. + *****************************************************************************/ +void log_debug(EVEL_LOG_LEVELS level, char * format, ...); + +/***************************************************************************//* + * Store the formatted string into the static error string and log the error. + * + * @param format Error string in standard printf format. + * @param ... Variable parameters to be substituted into the format string. + *****************************************************************************/ +void log_error_state(char * format, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vnfs/VES/code/evel_library/evel_event.c b/vnfs/VES/code/evel_library/evel_event.c new file mode 100644 index 00000000..2e49870f --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_event.c @@ -0,0 +1,568 @@ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to Event Headers - since + * Heartbeats only contain the Event Header, the Heartbeat factory function is + * here too. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include +#include + +#include "evel.h" +#include "evel_internal.h" +#include "evel_throttle.h" +#include "metadata.h" + +/**************************************************************************//** + * Unique sequence number for events from this VNF. + *****************************************************************************/ +static int event_sequence = 1; + +/**************************************************************************//** + * Set the next event_sequence to use. + * + * @param sequence The next sequence number to use. + *****************************************************************************/ +void evel_set_next_event_sequence(const int sequence) +{ + EVEL_ENTER(); + + EVEL_INFO("Setting event sequence to %d, was %d ", sequence, event_sequence); + event_sequence = sequence; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Create a new heartbeat event. + * + * @note that the heartbeat is just a "naked" commonEventHeader! + * + * @returns pointer to the newly manufactured ::EVENT_HEADER. If the event is + * not used it must be released using ::evel_free_event + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_HEADER * evel_new_heartbeat() +{ + EVENT_HEADER * heartbeat = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Allocate the header. */ + /***************************************************************************/ + heartbeat = malloc(sizeof(EVENT_HEADER)); + if (heartbeat == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(heartbeat, 0, sizeof(EVENT_HEADER)); + + /***************************************************************************/ + /* Initialize the header. Get a new event sequence number. Note that if */ + /* any memory allocation fails in here we will fail gracefully because */ + /* everything downstream can cope with NULLs. */ + /***************************************************************************/ + evel_init_header(heartbeat); + evel_force_option_string(&heartbeat->event_type, "Autonomous heartbeat"); + +exit_label: + EVEL_EXIT(); + return heartbeat; +} + +/**************************************************************************//** + * Initialize a newly created event header. + * + * @param header Pointer to the header being initialized. + *****************************************************************************/ +void evel_init_header(EVENT_HEADER * const header) +{ + char scratchpad[EVEL_MAX_STRING_LEN + 1] = {0}; + struct timeval tv; + + EVEL_ENTER(); + + assert(header != NULL); + + gettimeofday(&tv, NULL); + + /***************************************************************************/ + /* Initialize the header. Get a new event sequence number. Note that if */ + /* any memory allocation fails in here we will fail gracefully because */ + /* everything downstream can cope with NULLs. */ + /***************************************************************************/ + header->event_domain = EVEL_DOMAIN_HEARTBEAT; + snprintf(scratchpad, EVEL_MAX_STRING_LEN, "%d", event_sequence); + header->event_id = strdup(scratchpad); + header->functional_role = strdup(functional_role); + header->last_epoch_microsec = tv.tv_usec + 1000000 * tv.tv_sec; + header->priority = EVEL_PRIORITY_NORMAL; + header->reporting_entity_name = strdup(openstack_vm_name()); + header->source_name = strdup(openstack_vm_name()); + header->sequence = event_sequence; + header->start_epoch_microsec = header->last_epoch_microsec; + header->major_version = EVEL_HEADER_MAJOR_VERSION; + header->minor_version = EVEL_HEADER_MINOR_VERSION; + event_sequence++; + + /***************************************************************************/ + /* Optional parameters. */ + /***************************************************************************/ + evel_init_option_string(&header->event_type); + evel_force_option_string(&header->reporting_entity_id, openstack_vm_uuid()); + evel_force_option_string(&header->source_id, openstack_vm_uuid()); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Event Type property of the event header. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_header_type_set(EVENT_HEADER * const header, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(header != NULL); + assert(type != NULL); + + evel_set_option_string(&header->event_type, type, "Event Type"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Start Epoch property of the event header. + * + * @note The Start Epoch defaults to the time of event creation. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param start_epoch_microsec + * The start epoch to set, in microseconds. + *****************************************************************************/ +void evel_start_epoch_set(EVENT_HEADER * const header, + const unsigned long long start_epoch_microsec) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and assign the new value. */ + /***************************************************************************/ + assert(header != NULL); + header->start_epoch_microsec = start_epoch_microsec; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Last Epoch property of the event header. + * + * @note The Last Epoch defaults to the time of event creation. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param last_epoch_microsec + * The last epoch to set, in microseconds. + *****************************************************************************/ +void evel_last_epoch_set(EVENT_HEADER * const header, + const unsigned long long last_epoch_microsec) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and assign the new value. */ + /***************************************************************************/ + assert(header != NULL); + header->last_epoch_microsec = last_epoch_microsec; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Reporting Entity Name property of the event header. + * + * @note The Reporting Entity Name defaults to the OpenStack VM Name. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param entity_name The entity name to set. + *****************************************************************************/ +void evel_reporting_entity_name_set(EVENT_HEADER * const header, + const char * const entity_name) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and assign the new value. */ + /***************************************************************************/ + assert(header != NULL); + assert(entity_name != NULL); + assert(header->reporting_entity_name != NULL); + + /***************************************************************************/ + /* Free the previously allocated memory and replace it with a copy of the */ + /* provided one. */ + /***************************************************************************/ + free(header->reporting_entity_name); + header->reporting_entity_name = strdup(entity_name); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Reporting Entity Id property of the event header. + * + * @note The Reporting Entity Id defaults to the OpenStack VM UUID. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param entity_id The entity id to set. + *****************************************************************************/ +void evel_reporting_entity_id_set(EVENT_HEADER * const header, + const char * const entity_id) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and assign the new value. */ + /***************************************************************************/ + assert(header != NULL); + assert(entity_id != NULL); + + /***************************************************************************/ + /* Free the previously allocated memory and replace it with a copy of the */ + /* provided one. Note that evel_force_option_string strdups entity_id. */ + /***************************************************************************/ + evel_free_option_string(&header->reporting_entity_id); + evel_force_option_string(&header->reporting_entity_id, entity_id); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the event as a JSON event object according to AT&T's schema. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_header(EVEL_JSON_BUFFER * jbuf, + EVENT_HEADER * event) +{ + char * domain; + char * priority; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(jbuf->json != NULL); + assert(jbuf->max_size > 0); + assert(event != NULL); + + domain = evel_event_domain(event->event_domain); + priority = evel_event_priority(event->priority); + evel_json_open_named_object(jbuf, "commonEventHeader"); + + /***************************************************************************/ + /* Mandatory fields. */ + /***************************************************************************/ + evel_enc_kv_string(jbuf, "domain", domain); + evel_enc_kv_string(jbuf, "eventId", event->event_id); + evel_enc_kv_string(jbuf, "functionalRole", event->functional_role); + evel_enc_kv_ull(jbuf, "lastEpochMicrosec", event->last_epoch_microsec); + evel_enc_kv_string(jbuf, "priority", priority); + evel_enc_kv_string( + jbuf, "reportingEntityName", event->reporting_entity_name); + evel_enc_kv_int(jbuf, "sequence", event->sequence); + evel_enc_kv_string(jbuf, "sourceName", event->source_name); + evel_enc_kv_ull(jbuf, "startEpochMicrosec", event->start_epoch_microsec); + evel_enc_version( + jbuf, "version", event->major_version, event->minor_version); + + /***************************************************************************/ + /* Optional fields. */ + /***************************************************************************/ + evel_enc_kv_opt_string(jbuf, "eventType", &event->event_type); + evel_enc_kv_opt_string( + jbuf, "reportingEntityId", &event->reporting_entity_id); + evel_enc_kv_opt_string(jbuf, "sourceId", &event->source_id); + + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free an event header. + * + * Free off the event header supplied. Will free all the contained allocated + * memory. + * + * @note It does not free the header itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_header(EVENT_HEADER * const event) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the public API. */ + /***************************************************************************/ + assert(event != NULL); + + /***************************************************************************/ + /* Free all internal strings. */ + /***************************************************************************/ + free(event->event_id); + evel_free_option_string(&event->event_type); + free(event->functional_role); + evel_free_option_string(&event->reporting_entity_id); + free(event->reporting_entity_name); + evel_free_option_string(&event->source_id); + free(event->source_name); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the event as a JSON event object according to AT&T's schema. + * + * @param json Pointer to where to store the JSON encoded data. + * @param max_size Size of storage available in json_body. + * @param event Pointer to the ::EVENT_HEADER to encode. + * @returns Number of bytes actually written. + *****************************************************************************/ +int evel_json_encode_event(char * json, + int max_size, + EVENT_HEADER * event) +{ + EVEL_JSON_BUFFER json_buffer; + EVEL_JSON_BUFFER * jbuf = &json_buffer; + EVEL_THROTTLE_SPEC * throttle_spec; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Get the latest throttle specification for the domain. */ + /***************************************************************************/ + throttle_spec = evel_get_throttle_spec(event->event_domain); + + /***************************************************************************/ + /* Initialize the JSON_BUFFER and open the top-level objects. */ + /***************************************************************************/ + evel_json_buffer_init(jbuf, json, max_size, throttle_spec); + evel_json_open_object(jbuf); + evel_json_open_named_object(jbuf, "event"); + + switch (event->event_domain) + { + case EVEL_DOMAIN_HEARTBEAT: + evel_json_encode_header(jbuf, event); + break; + + case EVEL_DOMAIN_FAULT: + evel_json_encode_fault(jbuf, (EVENT_FAULT *)event); + break; + + case EVEL_DOMAIN_MEASUREMENT: + evel_json_encode_measurement(jbuf, (EVENT_MEASUREMENT *)event); + break; + + case EVEL_DOMAIN_MOBILE_FLOW: + evel_json_encode_mobile_flow(jbuf, (EVENT_MOBILE_FLOW *)event); + break; + + case EVEL_DOMAIN_REPORT: + evel_json_encode_report(jbuf, (EVENT_REPORT *)event); + break; + + case EVEL_DOMAIN_SERVICE: + evel_json_encode_service(jbuf, (EVENT_SERVICE *)event); + break; + + case EVEL_DOMAIN_SIGNALING: + evel_json_encode_signaling(jbuf, (EVENT_SIGNALING *)event); + break; + + case EVEL_DOMAIN_STATE_CHANGE: + evel_json_encode_state_change(jbuf, (EVENT_STATE_CHANGE *)event); + break; + + case EVEL_DOMAIN_SYSLOG: + evel_json_encode_syslog(jbuf, (EVENT_SYSLOG *)event); + break; + + case EVEL_DOMAIN_OTHER: + evel_json_encode_other(jbuf, (EVENT_OTHER *)event); + break; + + case EVEL_DOMAIN_INTERNAL: + default: + EVEL_ERROR("Unexpected domain %d", event->event_domain); + assert(0); + } + + evel_json_close_object(jbuf); + evel_json_close_object(jbuf); + + /***************************************************************************/ + /* Sanity check. */ + /***************************************************************************/ + assert(jbuf->depth == 0); + + EVEL_EXIT(); + + return jbuf->offset; +} + +/**************************************************************************//** + * Initialize an event instance id. + * + * @param instance_id Pointer to the event instance id being initialized. + * @param vendor_id The vendor id to encode in the event instance id. + * @param event_id The event id to encode in the event instance id. + *****************************************************************************/ +void evel_init_event_instance_id(EVEL_EVENT_INSTANCE_ID * const instance_id, + const char * const vendor_id, + const char * const event_id) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(instance_id != NULL); + assert(vendor_id != NULL); + assert(event_id != NULL); + + /***************************************************************************/ + /* Store the mandatory parts. */ + /***************************************************************************/ + instance_id->vendor_id = strdup(vendor_id); + instance_id->event_id = strdup(event_id); + + /***************************************************************************/ + /* Initialize the optional parts. */ + /***************************************************************************/ + evel_init_option_string(&instance_id->product_id); + evel_init_option_string(&instance_id->subsystem_id); + evel_init_option_string(&instance_id->event_friendly_name); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free an event instance id. + * + * @param instance_id Pointer to the event instance id being initialized. + *****************************************************************************/ +void evel_free_event_instance_id(EVEL_EVENT_INSTANCE_ID * const instance_id) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(instance_id != NULL); + assert(instance_id->vendor_id != NULL); + assert(instance_id->event_id != NULL); + + /***************************************************************************/ + /* Free everything. */ + /***************************************************************************/ + free(instance_id->vendor_id); + free(instance_id->event_id); + evel_free_option_string(&instance_id->product_id); + evel_free_option_string(&instance_id->subsystem_id); + evel_free_option_string(&instance_id->event_friendly_name); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the instance id as a JSON object according to AT&T's schema. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param instance_id Pointer to the ::EVEL_EVENT_INSTANCE_ID to encode. + *****************************************************************************/ +void evel_json_encode_instance_id(EVEL_JSON_BUFFER * jbuf, + EVEL_EVENT_INSTANCE_ID * instance_id) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(jbuf->json != NULL); + assert(jbuf->max_size > 0); + assert(instance_id != NULL); + assert(instance_id->vendor_id != NULL); + assert(instance_id->event_id != NULL); + + evel_json_open_named_object(jbuf, "eventInstanceIdentifier"); + + /***************************************************************************/ + /* Mandatory fields. */ + /***************************************************************************/ + evel_enc_kv_string(jbuf, "vendorId", instance_id->vendor_id); + evel_enc_kv_string(jbuf, "eventId", instance_id->event_id); + + /***************************************************************************/ + /* Optional fields. */ + /***************************************************************************/ + evel_enc_kv_opt_string(jbuf, "productId", &instance_id->product_id); + evel_enc_kv_opt_string(jbuf, "subsystemId", &instance_id->subsystem_id); + evel_enc_kv_opt_string( + jbuf, "eventFriendlyName", &instance_id->event_friendly_name); + + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} diff --git a/vnfs/VES/code/evel_library/evel_event_mgr.c b/vnfs/VES/code/evel_library/evel_event_mgr.c new file mode 100644 index 00000000..0cc049f5 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_event_mgr.c @@ -0,0 +1,1053 @@ +/**************************************************************************//** + * @file + * Event Manager + * + * Simple event manager that is responsible for taking events (Heartbeats, + * Faults and Measurements) from the ring-buffer and posting them to the API. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*****************************************************************************/ + +#include +#include +#include +#include + +#include + +#include "evel.h" +#include "evel_internal.h" +#include "ring_buffer.h" +#include "evel_throttle.h" + +/**************************************************************************//** + * How long we're prepared to wait for the API service to respond in + * seconds. + *****************************************************************************/ +static const int EVEL_API_TIMEOUT = 5; + +/*****************************************************************************/ +/* Prototypes of locally scoped functions. */ +/*****************************************************************************/ +static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp); +static void * event_handler(void *arg); +static bool evel_handle_response_tokens(const MEMORY_CHUNK * const chunk, + const jsmntok_t * const json_tokens, + const int num_tokens, + MEMORY_CHUNK * const post); +static bool evel_tokens_match_command_list(const MEMORY_CHUNK * const chunk, + const jsmntok_t * const json_token, + const int num_tokens); +static bool evel_token_equals_string(const MEMORY_CHUNK * const chunk, + const jsmntok_t * const json_token, + const char * check_string); + +/**************************************************************************//** + * Buffers for error strings from libcurl. + *****************************************************************************/ +static char curl_err_string[CURL_ERROR_SIZE] = ""; + +/**************************************************************************//** + * Handle for the API into libcurl. + *****************************************************************************/ +static CURL * curl_handle = NULL; + +/**************************************************************************//** + * Special headers that we send. + *****************************************************************************/ +static struct curl_slist * hdr_chunk = NULL; + +/**************************************************************************//** + * Message queue for sending events to the API. + *****************************************************************************/ +static ring_buffer event_buffer; + +/**************************************************************************//** + * Single pending priority post, which can be generated as a result of a + * response to an event. Currently only used to respond to a commandList. + *****************************************************************************/ +static MEMORY_CHUNK priority_post; + +/**************************************************************************//** + * The thread which is responsible for handling events off of the ring-buffer + * and posting them to the Event Handler API. + *****************************************************************************/ +static pthread_t evt_handler_thread; + +/**************************************************************************//** + * Variable to convey to the event handler thread what the foreground wants it + * to do. + *****************************************************************************/ +static EVT_HANDLER_STATE evt_handler_state = EVT_HANDLER_UNINITIALIZED; + +/**************************************************************************//** + * The configured API URL for event and throttling. + *****************************************************************************/ +static char * evel_event_api_url; +static char * evel_throt_api_url; + +/**************************************************************************//** + * Initialize the event handler. + * + * Primarily responsible for getting CURL ready for use. + * + * @param[in] event_api_url + * The URL where the Vendor Event Listener API is expected + * to be. + * @param[in] throt_api_url + * The URL where the Throttling API is expected to be. + * @param[in] username The username for the Basic Authentication of requests. + * @param[in] password The password for the Basic Authentication of requests. + * @param verbosity 0 for normal operation, positive values for chattier + * logs. + *****************************************************************************/ +EVEL_ERR_CODES event_handler_initialize(const char * const event_api_url, + const char * const throt_api_url, + const char * const username, + const char * const password, + int verbosity) +{ + int rc = EVEL_SUCCESS; + CURLcode curl_rc = CURLE_OK; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(event_api_url != NULL); + assert(throt_api_url != NULL); + assert(username != NULL); + assert(password != NULL); + + /***************************************************************************/ + /* Store the API URLs. */ + /***************************************************************************/ + evel_event_api_url = strdup(event_api_url); + assert(evel_event_api_url != NULL); + evel_throt_api_url = strdup(throt_api_url); + assert(evel_throt_api_url != NULL); + + /***************************************************************************/ + /* Start the CURL library. Note that this initialization is not threadsafe */ + /* which imposes a constraint that the EVEL library is initialized before */ + /* any threads are started. */ + /***************************************************************************/ + curl_rc = curl_global_init(CURL_GLOBAL_SSL); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL. Error code=%d", curl_rc); + goto exit_label; + } + + /***************************************************************************/ + /* Get a curl handle which we'll use for all of our output. */ + /***************************************************************************/ + curl_handle = curl_easy_init(); + if (curl_handle == NULL) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to get libCURL handle"); + goto exit_label; + } + + /***************************************************************************/ + /* Prime the library to give friendly error codes. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, + CURLOPT_ERRORBUFFER, + curl_err_string); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL to provide friendly errors. " + "Error code=%d", curl_rc); + goto exit_label; + } + + /***************************************************************************/ + /* If running in verbose mode generate more output. */ + /***************************************************************************/ + if (verbosity > 0) + { + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL to be verbose. " + "Error code=%d", curl_rc); + goto exit_label; + } + } + + /***************************************************************************/ + /* Set the URL for the API. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, event_api_url); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL with the API URL. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + EVEL_INFO("Initializing CURL to send events to: %s", event_api_url); + + /***************************************************************************/ + /* send all data to this function. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, + CURLOPT_WRITEFUNCTION, + evel_write_callback); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL with the write callback. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + + /***************************************************************************/ + /* some servers don't like requests that are made without a user-agent */ + /* field, so we provide one. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, + CURLOPT_USERAGENT, + "libcurl-agent/1.0"); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL to upload. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + + /***************************************************************************/ + /* Specify that we are going to POST data. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_POST, 1L); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL to upload. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + + /***************************************************************************/ + /* we want to use our own read function. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION, read_callback); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL to upload using read " + "function. Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + + /***************************************************************************/ + /* All of our events are JSON encoded. We also suppress the */ + /* Expect: 100-continue header that we would otherwise get since it */ + /* confuses some servers. */ + /* */ + /* @TODO: do AT&T want this behavior? */ + /***************************************************************************/ + hdr_chunk = curl_slist_append(hdr_chunk, "Content-type: application/json"); + hdr_chunk = curl_slist_append(hdr_chunk, "Expect:"); + + /***************************************************************************/ + /* set our custom set of headers. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, hdr_chunk); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL to use custom headers. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + + /***************************************************************************/ + /* Set the timeout for the operation. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, + CURLOPT_TIMEOUT, + EVEL_API_TIMEOUT); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL for API timeout. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + + /***************************************************************************/ + /* Set that we want Basic authentication with username:password Base-64 */ + /* encoded for the operation. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL for Basic Authentication. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_USERNAME, username); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL with username. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_PASSWORD, password); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL with password. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + + /***************************************************************************/ + /* Initialize a message ring-buffer to be used between the foreground and */ + /* the thread which sends the messages. This can't fail. */ + /***************************************************************************/ + ring_buffer_initialize(&event_buffer, EVEL_EVENT_BUFFER_DEPTH); + + /***************************************************************************/ + /* Initialize the priority post buffer to empty. */ + /***************************************************************************/ + priority_post.memory = NULL; + +exit_label: + EVEL_EXIT(); + + return(rc); +} + +/**************************************************************************//** + * Run the event handler. + * + * Spawns the thread responsible for handling events and sending them to the + * API. + * + * @return Status code. + * @retval ::EVEL_SUCCESS if everything OK. + * @retval One of ::EVEL_ERR_CODES if there was a problem. + *****************************************************************************/ +EVEL_ERR_CODES event_handler_run() +{ + EVEL_ERR_CODES rc = EVEL_SUCCESS; + int pthread_rc = 0; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Start the event handler thread. */ + /***************************************************************************/ + evt_handler_state = EVT_HANDLER_INACTIVE; + pthread_rc = pthread_create(&evt_handler_thread, NULL, event_handler, NULL); + if (pthread_rc != 0) + { + rc = EVEL_PTHREAD_LIBRARY_FAIL; + log_error_state("Failed to start event handler thread. " + "Error code=%d", pthread_rc); + } + + EVEL_EXIT() + return rc; +} + +/**************************************************************************//** + * Terminate the event handler. + * + * Shuts down the event handler thread in as clean a way as possible. Sets the + * global exit flag and then signals the thread to interrupt it since it's + * most likely waiting on the ring-buffer. + * + * Having achieved an orderly shutdown of the event handler thread, clean up + * the cURL library's resources cleanly. + * + * @return Status code. + * @retval ::EVEL_SUCCESS if everything OK. + * @retval One of ::EVEL_ERR_CODES if there was a problem. + *****************************************************************************/ +EVEL_ERR_CODES event_handler_terminate() +{ + EVEL_ERR_CODES rc = EVEL_SUCCESS; + + EVEL_ENTER(); + EVENT_INTERNAL *event = NULL; + + /***************************************************************************/ + /* Make sure that we were initialized before trying to terminate the */ + /* event handler thread. */ + /***************************************************************************/ + if (evt_handler_state != EVT_HANDLER_UNINITIALIZED) + { + /*************************************************************************/ + /* Make sure that the event handler knows it's time to die. */ + /*************************************************************************/ + event = evel_new_internal_event(EVT_CMD_TERMINATE); + if (event == NULL) + { + /***********************************************************************/ + /* We failed to get an event, but we don't bail out - we will just */ + /* clean up what we can and continue on our way, since we're exiting */ + /* anyway. */ + /***********************************************************************/ + EVEL_ERROR("Failed to get internal event - perform dirty exit instead!"); + } + else + { + /***********************************************************************/ + /* Post the event then wait for the Event Handler to exit. Set the */ + /* global command, too, in case the ring-buffer is full. */ + /***********************************************************************/ + EVEL_DEBUG("Sending event to Event Hander to request it to exit."); + evt_handler_state = EVT_HANDLER_REQUEST_TERMINATE; + evel_post_event((EVENT_HEADER *) event); + pthread_join(evt_handler_thread, NULL); + EVEL_DEBUG("Event Handler thread has exited."); + } + } + else + { + EVEL_DEBUG("Event handler was not initialized, so no need to kill it"); + } + + /***************************************************************************/ + /* Clean-up the cURL library. */ + /***************************************************************************/ + if (curl_handle != NULL) + { + curl_easy_cleanup(curl_handle); + curl_handle = NULL; + } + if (hdr_chunk != NULL) + { + curl_slist_free_all(hdr_chunk); + hdr_chunk = NULL; + } + + /***************************************************************************/ + /* Free off the stored API URL strings. */ + /***************************************************************************/ + if (evel_event_api_url != NULL) + { + free(evel_event_api_url); + evel_event_api_url = NULL; + } + if (evel_throt_api_url != NULL) + { + free(evel_throt_api_url); + evel_throt_api_url = NULL; + } + + EVEL_EXIT(); + return rc; +} + +/**************************************************************************//** + * Post an event. + * + * @note So far as the caller is concerned, successfully posting the event + * relinquishes all responsibility for the event - the library will take care + * of freeing the event in due course. + + * @param event The event to be posted. + * + * @returns Status code + * @retval EVEL_SUCCESS On success + * @retval "One of ::EVEL_ERR_CODES" On failure. + *****************************************************************************/ +EVEL_ERR_CODES evel_post_event(EVENT_HEADER * event) +{ + int rc = EVEL_SUCCESS; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + + /***************************************************************************/ + /* We need to make sure that we are either initializing or running */ + /* normally before writing the event into the buffer so that we can */ + /* guarantee that the ring-buffer empties properly on exit. */ + /***************************************************************************/ + if ((evt_handler_state == EVT_HANDLER_ACTIVE) || + (evt_handler_state == EVT_HANDLER_INACTIVE) || + (evt_handler_state == EVT_HANDLER_REQUEST_TERMINATE)) + { + if (ring_buffer_write(&event_buffer, event) == 0) + { + log_error_state("Failed to write event to buffer - event dropped!"); + rc = EVEL_EVENT_BUFFER_FULL; + evel_free_event(event); + } + } + else + { + /*************************************************************************/ + /* System is not in active operation, so reject the event. */ + /*************************************************************************/ + log_error_state("Event Handler system not active - event dropped!"); + rc = EVEL_EVENT_HANDLER_INACTIVE; + evel_free_event(event); + } + + EVEL_EXIT(); + return (rc); +} + +/**************************************************************************//** + * Post an event to the Vendor Event Listener API. + * + * @returns Status code + * @retval EVEL_SUCCESS On success + * @retval "One of ::EVEL_ERR_CODES" On failure. + *****************************************************************************/ +static EVEL_ERR_CODES evel_post_api(char * msg, size_t size) +{ + int rc = EVEL_SUCCESS; + CURLcode curl_rc = CURLE_OK; + MEMORY_CHUNK rx_chunk; + MEMORY_CHUNK tx_chunk; + int http_response_code = 0; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Create the memory chunk to be used for the response to the post. The */ + /* will be realloced. */ + /***************************************************************************/ + rx_chunk.memory = malloc(1); + assert(rx_chunk.memory != NULL); + rx_chunk.size = 0; + + /***************************************************************************/ + /* Create the memory chunk to be sent as the body of the post. */ + /***************************************************************************/ + tx_chunk.memory = msg; + tx_chunk.size = size; + EVEL_DEBUG("Sending chunk of size %d", tx_chunk.size); + + /***************************************************************************/ + /* Point to the data to be received. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &rx_chunk); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libCURL to upload. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + EVEL_DEBUG("Initialized data to receive"); + + /***************************************************************************/ + /* Pointer to pass to our read function */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_READDATA, &tx_chunk); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to set upload data for libCURL to upload. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + EVEL_DEBUG("Initialized data to send"); + + /***************************************************************************/ + /* Size of the data to transmit. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, + CURLOPT_POSTFIELDSIZE, + tx_chunk.size); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to set length of upload data for libCURL to " + "upload. Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + EVEL_DEBUG("Initialized length of data to send"); + + /***************************************************************************/ + /* Now run off and do what you've been told! */ + /***************************************************************************/ + curl_rc = curl_easy_perform(curl_handle); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to transfer an event to Vendor Event Listener! " + "Error code=%d (%s)", curl_rc, curl_err_string); + EVEL_ERROR("Dropped event: %s", msg); + goto exit_label; + } + + /***************************************************************************/ + /* See what response we got - any 2XX response is good. */ + /***************************************************************************/ + curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_response_code); + EVEL_DEBUG("HTTP response code: %d", http_response_code); + if ((http_response_code / 100) == 2) + { + /*************************************************************************/ + /* If the server responded with data it may be interesting but not a */ + /* problem. */ + /*************************************************************************/ + if ((rx_chunk.size > 0) && (rx_chunk.memory != NULL)) + { + EVEL_DEBUG("Server returned data = %d (%s)", + rx_chunk.size, + rx_chunk.memory); + + /***********************************************************************/ + /* If this is a response to priority post, then we're not interested. */ + /***********************************************************************/ + if (priority_post.memory != NULL) + { + EVEL_ERROR("Ignoring priority post response"); + } + else + { + evel_handle_event_response(&rx_chunk, &priority_post); + } + } + } + else + { + EVEL_ERROR("Unexpected HTTP response code: %d with data size %d (%s)", + http_response_code, + rx_chunk.size, + rx_chunk.size > 0 ? rx_chunk.memory : "NONE"); + EVEL_ERROR("Potentially dropped event: %s", msg); + } + +exit_label: + free(rx_chunk.memory); + EVEL_EXIT(); + return(rc); +} + +/**************************************************************************//** + * Callback function to provide data to send. + * + * Copy data into the supplied buffer, read_callback::ptr, checking size + * limits. + * + * @returns Number of bytes placed into read_callback::ptr. 0 for EOF. + *****************************************************************************/ +static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp) +{ + size_t rtn = 0; + size_t bytes_to_write = 0; + MEMORY_CHUNK *tx_chunk = (MEMORY_CHUNK *)userp; + + EVEL_ENTER(); + + bytes_to_write = min(size*nmemb, tx_chunk->size); + + if (bytes_to_write > 0) + { + EVEL_DEBUG("Going to try to write %d bytes", bytes_to_write); + strncpy((char *)ptr, tx_chunk->memory, bytes_to_write); + tx_chunk->memory += bytes_to_write; + tx_chunk->size -= bytes_to_write; + rtn = bytes_to_write; + } + else + { + EVEL_DEBUG("Reached EOF"); + } + + EVEL_EXIT(); + return rtn; +} + +/**************************************************************************//** + * Callback function to provide returned data. + * + * Copy data into the supplied buffer, write_callback::ptr, checking size + * limits. + * + * @returns Number of bytes placed into write_callback::ptr. 0 for EOF. + *****************************************************************************/ +size_t evel_write_callback(void *contents, + size_t size, + size_t nmemb, + void *userp) +{ + size_t realsize = size * nmemb; + MEMORY_CHUNK * rx_chunk = (MEMORY_CHUNK *)userp; + + EVEL_ENTER(); + + EVEL_DEBUG("Called with %d chunks of %d size = %d", nmemb, size, realsize); + EVEL_DEBUG("rx chunk size is %d", rx_chunk->size); + + rx_chunk->memory = realloc(rx_chunk->memory, rx_chunk->size + realsize + 1); + if(rx_chunk->memory == NULL) { + /* out of memory! */ + printf("not enough memory (realloc returned NULL)\n"); + return 0; + } + + memcpy(&(rx_chunk->memory[rx_chunk->size]), contents, realsize); + rx_chunk->size += realsize; + rx_chunk->memory[rx_chunk->size] = 0; + + EVEL_DEBUG("Rx data: %s", rx_chunk->memory); + EVEL_DEBUG("Returning: %d", realsize); + + EVEL_EXIT(); + return realsize; +} + +/**************************************************************************//** + * Event Handler. + * + * Watch for messages coming on the internal queue and send them to the + * listener. + * + * param[in] arg Argument - unused. + *****************************************************************************/ +static void * event_handler(void * arg __attribute__ ((unused))) +{ + int old_type = 0; + EVENT_HEADER * msg = NULL; + EVENT_INTERNAL * internal_msg = NULL; + int json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + int rc = EVEL_SUCCESS; + CURLcode curl_rc; + + EVEL_INFO("Event handler thread started"); + + /***************************************************************************/ + /* Set this thread to be cancellable immediately. */ + /***************************************************************************/ + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type); + + /***************************************************************************/ + /* Set the handler as active, defending against weird situations like */ + /* immediately shutting down after initializing the library so the */ + /* handler never gets started up properly. */ + /***************************************************************************/ + if (evt_handler_state == EVT_HANDLER_INACTIVE) + { + evt_handler_state = EVT_HANDLER_ACTIVE; + } + else + { + EVEL_ERROR("Event Handler State was not INACTIVE at start-up - " + "Handler will exit immediately!"); + } + + while (evt_handler_state == EVT_HANDLER_ACTIVE) + { + /*************************************************************************/ + /* Wait for a message to be received. */ + /*************************************************************************/ + EVEL_DEBUG("Event handler getting any messages"); + msg = ring_buffer_read(&event_buffer); + + /*************************************************************************/ + /* Internal events get special treatment while regular events get posted */ + /* to the far side. */ + /*************************************************************************/ + if (msg->event_domain != EVEL_DOMAIN_INTERNAL) + { + EVEL_DEBUG("External event received"); + + /***********************************************************************/ + /* Encode the event in JSON. */ + /***********************************************************************/ + json_size = evel_json_encode_event(json_body, EVEL_MAX_JSON_BODY, msg); + + /***********************************************************************/ + /* Send the JSON across the API. */ + /***********************************************************************/ + EVEL_DEBUG("Sending JSON of size %d is: %s", json_size, json_body); + rc = evel_post_api(json_body, json_size); + if (rc != EVEL_SUCCESS) + { + EVEL_ERROR("Failed to transfer the data. Error code=%d", rc); + } + } + else + { + EVEL_DEBUG("Internal event received"); + internal_msg = (EVENT_INTERNAL *) msg; + assert(internal_msg->command == EVT_CMD_TERMINATE); + evt_handler_state = EVT_HANDLER_TERMINATING; + } + + /*************************************************************************/ + /* We are responsible for freeing the memory. */ + /*************************************************************************/ + evel_free_event(msg); + msg = NULL; + + /*************************************************************************/ + /* There may be a single priority post to be sent. */ + /*************************************************************************/ + if (priority_post.memory != NULL) + { + EVEL_DEBUG("Priority Post"); + + /***********************************************************************/ + /* Set the URL for the throttling API. */ + /***********************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_throt_api_url); + if (curl_rc != CURLE_OK) + { + /*********************************************************************/ + /* This is only likely to happen with CURLE_OUT_OF_MEMORY, in which */ + /* case we carry on regardless. */ + /*********************************************************************/ + EVEL_ERROR("Failed to set throttling URL. Error code=%d", rc); + } + else + { + rc = evel_post_api(priority_post.memory, priority_post.size); + if (rc != EVEL_SUCCESS) + { + EVEL_ERROR("Failed to transfer priority post. Error code=%d", rc); + } + } + + /***********************************************************************/ + /* Reinstate the URL for the event API. */ + /***********************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_event_api_url); + if (curl_rc != CURLE_OK) + { + /*********************************************************************/ + /* This is only likely to happen with CURLE_OUT_OF_MEMORY, in which */ + /* case we carry on regardless. */ + /*********************************************************************/ + EVEL_ERROR("Failed to reinstate events URL. Error code=%d", rc); + } + + /***********************************************************************/ + /* We are responsible for freeing the memory. */ + /***********************************************************************/ + free(priority_post.memory); + priority_post.memory = NULL; + } + } + + /***************************************************************************/ + /* The event handler is now exiting. The ring-buffer could contain events */ + /* which have not been processed, so deplete those. Because we've been */ + /* asked to exit we can be confident that the foreground will have stopped */ + /* sending events in so we know that this process will conclude! */ + /***************************************************************************/ + evt_handler_state = EVT_HANDLER_TERMINATING; + while (!ring_buffer_is_empty(&event_buffer)) + { + EVEL_DEBUG("Reading event from buffer"); + msg = ring_buffer_read(&event_buffer); + evel_free_event(msg); + } + evt_handler_state = EVT_HANDLER_TERMINATED; + EVEL_INFO("Event handler thread stopped"); + + return (NULL); +} + +/**************************************************************************//** + * Handle a JSON response from the listener, contained in a ::MEMORY_CHUNK. + * + * Tokenize the response, and decode any tokens found. + * + * @param chunk The memory chunk containing the response. + * @param post The memory chunk in which to place any resulting POST. + *****************************************************************************/ +void evel_handle_event_response(const MEMORY_CHUNK * const chunk, + MEMORY_CHUNK * const post) +{ + jsmn_parser json_parser; + jsmntok_t json_tokens[EVEL_MAX_RESPONSE_TOKENS]; + int num_tokens = 0; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(chunk != NULL); + assert(priority_post.memory == NULL); + + EVEL_DEBUG("Response size = %d", chunk->size); + EVEL_DEBUG("Response = %s", chunk->memory); + + /***************************************************************************/ + /* Initialize the parser and tokenize the response. */ + /***************************************************************************/ + jsmn_init(&json_parser); + num_tokens = jsmn_parse(&json_parser, + chunk->memory, + chunk->size, + json_tokens, + EVEL_MAX_RESPONSE_TOKENS); + + if (num_tokens < 0) + { + EVEL_ERROR("Failed to parse JSON response. " + "Error code=%d", num_tokens); + } + else if (num_tokens == 0) + { + EVEL_DEBUG("No tokens found in JSON response"); + } + else + { + EVEL_DEBUG("Decode JSON response tokens"); + if (!evel_handle_response_tokens(chunk, json_tokens, num_tokens, post)) + { + EVEL_ERROR("Failed to handle JSON response."); + } + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Handle a JSON response from the listener, as a list of tokens from JSMN. + * + * @param chunk Memory chunk containing the JSON buffer. + * @param json_tokens Array of tokens to handle. + * @param num_tokens The number of tokens to handle. + * @param post The memory chunk in which to place any resulting POST. + * @return true if we handled the response, false otherwise. + *****************************************************************************/ +bool evel_handle_response_tokens(const MEMORY_CHUNK * const chunk, + const jsmntok_t * const json_tokens, + const int num_tokens, + MEMORY_CHUNK * const post) +{ + bool json_ok = false; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(chunk != NULL); + assert(json_tokens != NULL); + assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS); + + /***************************************************************************/ + /* Peek at the tokens to decide what the response it, then call the */ + /* appropriate handler to handle it. There is only one handler at this */ + /* point. */ + /***************************************************************************/ + if (evel_tokens_match_command_list(chunk, json_tokens, num_tokens)) + { + json_ok = evel_handle_command_list(chunk, json_tokens, num_tokens, post); + } + + EVEL_EXIT(); + + return json_ok; +} + +/**************************************************************************//** + * Determine whether a list of tokens looks like a "commandList" response. + * + * @param chunk Memory chunk containing the JSON buffer. + * @param json_tokens Token to check. + * @param num_tokens The number of tokens to handle. + * @return true if the tokens look like a "commandList" match, or false. + *****************************************************************************/ +bool evel_tokens_match_command_list(const MEMORY_CHUNK * const chunk, + const jsmntok_t * const json_tokens, + const int num_tokens) +{ + bool result = false; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Make some checks on the basic layout of the commandList. */ + /***************************************************************************/ + if ((num_tokens > 3) && + (json_tokens[0].type == JSMN_OBJECT) && + (json_tokens[1].type == JSMN_STRING) && + (json_tokens[2].type == JSMN_ARRAY) && + (evel_token_equals_string(chunk, &json_tokens[1], "commandList"))) + { + result = true; + } + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Check that a string token matches a given input string. + * + * @param chunk Memory chunk containing the JSON buffer. + * @param json_token Token to check. + * @param check_string String to check it against. + * @return true if the strings match, or false. + *****************************************************************************/ +bool evel_token_equals_string(const MEMORY_CHUNK * const chunk, + const jsmntok_t * json_token, + const char * check_string) +{ + bool result = false; + + EVEL_ENTER(); + + const int token_length = json_token->end - json_token->start; + const char * const token_string = chunk->memory + json_token->start; + + if (token_length == (int)strlen(check_string)) + { + result = (strncmp(token_string, check_string, token_length) == 0); + } + + EVEL_EXIT(); + + return result; +} diff --git a/vnfs/VES/code/evel_library/evel_fault.c b/vnfs/VES/code/evel_library/evel_fault.c new file mode 100644 index 00000000..cbb80d71 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_fault.c @@ -0,0 +1,337 @@ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the Fault. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include + +#include "evel.h" +#include "evel_internal.h" +#include "evel_throttle.h" + +/**************************************************************************//** + * Create a new fault event. + * + * @note The mandatory fields on the Fault must be supplied to this factory + * function and are immutable once set. Optional fields have explicit + * setter functions, but again values may only be set once so that the + * Fault has immutable properties. + * @param condition The condition indicated by the Fault. + * @param specific_problem The specific problem triggering the fault. + * @param priority The priority of the event. + * @param severity The severity of the Fault. + * @returns pointer to the newly manufactured ::EVENT_FAULT. If the event is + * not used (i.e. posted) it must be released using ::evel_free_fault. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_FAULT * evel_new_fault(const char * const condition, + const char * const specific_problem, + EVEL_EVENT_PRIORITIES priority, + EVEL_SEVERITIES severity) +{ + EVENT_FAULT * fault = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(condition != NULL); + assert(specific_problem != NULL); + assert(priority < EVEL_MAX_PRIORITIES); + assert(severity < EVEL_MAX_SEVERITIES); + + /***************************************************************************/ + /* Allocate the fault. */ + /***************************************************************************/ + fault = malloc(sizeof(EVENT_FAULT)); + if (fault == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(fault, 0, sizeof(EVENT_FAULT)); + EVEL_DEBUG("New fault is at %lp", fault); + + /***************************************************************************/ + /* Initialize the header & the fault fields. Optional string values are */ + /* uninitialized (NULL). */ + /***************************************************************************/ + evel_init_header(&fault->header); + fault->header.event_domain = EVEL_DOMAIN_FAULT; + fault->header.priority = priority; + fault->major_version = EVEL_FAULT_MAJOR_VERSION; + fault->minor_version = EVEL_FAULT_MINOR_VERSION; + fault->event_severity = severity; + fault->event_source_type = event_source_type; + fault->vf_status = EVEL_VF_STATUS_ACTIVE; + fault->alarm_condition = strdup(condition); + fault->specific_problem = strdup(specific_problem); + evel_init_option_string(&fault->alarm_interface_a); + dlist_initialize(&fault->additional_info); + +exit_label: + EVEL_EXIT(); + return fault; +} + +/**************************************************************************//** + * Add an additional value name/value pair to the Fault. + * + * The name and value are null delimited ASCII strings. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param fault Pointer to the fault. + * @param name ASCIIZ string with the attribute's name. The caller + * does not need to preserve the value once the function + * returns. + * @param value ASCIIZ string with the attribute's value. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_fault_addl_info_add(EVENT_FAULT * fault, char * name, char * value) +{ + FAULT_ADDL_INFO * addl_info = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(fault != NULL); + assert(fault->header.event_domain == EVEL_DOMAIN_FAULT); + assert(name != NULL); + assert(value != NULL); + + EVEL_DEBUG("Adding name=%s value=%s", name, value); + addl_info = malloc(sizeof(FAULT_ADDL_INFO)); + assert(addl_info != NULL); + memset(addl_info, 0, sizeof(FAULT_ADDL_INFO)); + addl_info->name = strdup(name); + addl_info->value = strdup(value); + assert(addl_info->name != NULL); + assert(addl_info->value != NULL); + + dlist_push_last(&fault->additional_info, addl_info); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Alarm Interface A property of the Fault. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param fault Pointer to the fault. + * @param interface The Alarm Interface A to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_fault_interface_set(EVENT_FAULT * fault, + const char * const interface) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(fault != NULL); + assert(fault->header.event_domain == EVEL_DOMAIN_FAULT); + assert(interface != NULL); + + evel_set_option_string(&fault->alarm_interface_a, + interface, + "Alarm Interface A"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Event Type property of the Fault. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param fault Pointer to the fault. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_fault_type_set(EVENT_FAULT * fault, const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(fault != NULL); + assert(fault->header.event_domain == EVEL_DOMAIN_FAULT); + evel_header_type_set(&fault->header, type); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the fault in JSON according to AT&T's schema for the fault type. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_fault(EVEL_JSON_BUFFER * jbuf, + EVENT_FAULT * event) +{ + FAULT_ADDL_INFO * addl_info = NULL; + DLIST_ITEM * addl_info_item = NULL; + char * fault_severity; + char * fault_source_type; + char * fault_vf_status; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_FAULT); + + fault_severity = evel_severity(event->event_severity); + fault_source_type = evel_source_type(event->event_source_type); + fault_vf_status = evel_vf_status(event->vf_status); + + evel_json_encode_header(jbuf, &event->header); + evel_json_open_named_object(jbuf, "faultFields"); + + /***************************************************************************/ + /* Mandatory fields. */ + /***************************************************************************/ + evel_enc_kv_string(jbuf, "alarmCondition", event->alarm_condition); + evel_enc_kv_string(jbuf, "eventSeverity", fault_severity); + evel_enc_kv_string(jbuf, "eventSourceType", fault_source_type); + evel_enc_kv_string(jbuf, "specificProblem", event->specific_problem); + evel_enc_kv_string(jbuf, "vfStatus", fault_vf_status); + evel_enc_version( + jbuf, "faultFieldsVersion", event->major_version, event->minor_version); + + /***************************************************************************/ + /* Optional fields. */ + /***************************************************************************/ + + /***************************************************************************/ + /* Checkpoint, so that we can wind back if all fields are suppressed. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "alarmAdditionalInformation")) + { + bool item_added = false; + + addl_info_item = dlist_get_first(&event->additional_info); + while (addl_info_item != NULL) + { + addl_info = (FAULT_ADDL_INFO*) addl_info_item->item; + assert(addl_info != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "alarmAdditionalInformation", + addl_info->name)) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "name", addl_info->name); + evel_enc_kv_string(jbuf, "value", addl_info->value); + evel_json_close_object(jbuf); + item_added = true; + } + addl_info_item = dlist_get_next(addl_info_item); + } + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + if (!item_added) + { + evel_json_rewind(jbuf); + } + } + evel_enc_kv_opt_string(jbuf, "alarmInterfaceA", &event->alarm_interface_a); + + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free a Fault. + * + * Free off the Fault supplied. Will free all the contained allocated memory. + * + * @note It does not free the Fault itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_fault(EVENT_FAULT * event) +{ + FAULT_ADDL_INFO * addl_info = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the public API. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_FAULT); + + /***************************************************************************/ + /* Free all internal strings then the header itself. */ + /***************************************************************************/ + addl_info = dlist_pop_last(&event->additional_info); + while (addl_info != NULL) + { + EVEL_DEBUG("Freeing Additional Info (%s, %s)", + addl_info->name, + addl_info->value); + free(addl_info->name); + free(addl_info->value); + free(addl_info); + addl_info = dlist_pop_last(&event->additional_info); + } + free(event->alarm_condition); + evel_free_option_string(&event->alarm_interface_a); + free(event->specific_problem); + evel_free_header(&event->header); + + EVEL_EXIT(); +} diff --git a/vnfs/VES/code/evel_library/evel_internal.h b/vnfs/VES/code/evel_library/evel_internal.h new file mode 100644 index 00000000..fc887c95 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_internal.h @@ -0,0 +1,867 @@ +#ifndef EVEL_INTERNAL_INCLUDED +#define EVEL_INTERNAL_INCLUDED + +/**************************************************************************//** + * @file + * EVEL internal definitions. + * + * These are internal definitions which need to be shared between modules + * within the library but are not intended for external consumption. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include "evel.h" + +/*****************************************************************************/ +/* Define some type-safe min/max macros. */ +/*****************************************************************************/ +#define max(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) + +#define min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + + +/**************************************************************************//** + * Compile-time assertion. + *****************************************************************************/ +#define EVEL_CT_ASSERT(X) switch (0) {case 0: case (X):;} + +/**************************************************************************//** + * The Functional Role of the equipment represented by this VNF. + *****************************************************************************/ +extern char * functional_role; + +/**************************************************************************//** + * The type of equipment represented by this VNF. + *****************************************************************************/ +extern EVEL_SOURCE_TYPES event_source_type; + +/**************************************************************************//** + * A chunk of memory used in the cURL functions. + *****************************************************************************/ +typedef struct memory_chunk { + char * memory; + size_t size; +} MEMORY_CHUNK; + +/**************************************************************************//** + * Global commands that may be sent to the Event Handler thread. + *****************************************************************************/ +typedef enum { + EVT_CMD_TERMINATE, + EVT_CMD_MAX_COMMANDS +} EVT_HANDLER_COMMAND; + +/**************************************************************************//** + * State of the Event Handler thread. + *****************************************************************************/ +typedef enum { + EVT_HANDLER_UNINITIALIZED, /** The library cannot handle events. */ + EVT_HANDLER_INACTIVE, /** The event handler thread not started. */ + EVT_HANDLER_ACTIVE, /** The event handler thread is started. */ + EVT_HANDLER_REQUEST_TERMINATE, /** Initial stages of shutdown. */ + EVT_HANDLER_TERMINATING, /** The ring-buffer is being depleted. */ + EVT_HANDLER_TERMINATED, /** The library is exited. */ + EVT_HANDLER_MAX_STATES /** Maximum number of valid states. */ +} EVT_HANDLER_STATE; + +/**************************************************************************//** + * Internal event. + * Pseudo-event used for routing internal commands. + *****************************************************************************/ +typedef struct event_internal { + EVENT_HEADER header; + EVT_HANDLER_COMMAND command; +} EVENT_INTERNAL; + +/**************************************************************************//** + * Suppressed NV pairs list entry. + * JSON equivalent field: suppressedNvPairs + *****************************************************************************/ +typedef struct evel_suppressed_nv_pairs { + + /***************************************************************************/ + /* Mandatory fields */ + /* JSON equivalent field: nvPairFieldName */ + /***************************************************************************/ + char * nv_pair_field_name; + + /***************************************************************************/ + /* Optional fields */ + /* JSON equivalent field: suppressedNvPairNames */ + /* Type of each list entry: char * */ + /***************************************************************************/ + DLIST suppressed_nv_pair_names; + + /***************************************************************************/ + /* Hash table containing suppressed_nv_pair_names as keys. */ + /***************************************************************************/ + struct hsearch_data * hash_nv_pair_names; + +} EVEL_SUPPRESSED_NV_PAIRS; + +/**************************************************************************//** + * Event Throttling Specification for a domain which is in a throttled state. + * JSON equivalent object: eventThrottlingState + *****************************************************************************/ +typedef struct evel_throttle_spec { + + /***************************************************************************/ + /* List of field names to be suppressed. */ + /* JSON equivalent field: suppressedFieldNames */ + /* Type of each list entry: char * */ + /***************************************************************************/ + DLIST suppressed_field_names; + + /***************************************************************************/ + /* List of name-value pairs to be suppressed. */ + /* JSON equivalent field: suppressedNvPairsList */ + /* Type of each list entry: EVEL_SUPPRESSED_NV_PAIRS * */ + /***************************************************************************/ + DLIST suppressed_nv_pairs_list; + + /***************************************************************************/ + /* Hash table containing suppressed_nv_pair_names as keys. */ + /***************************************************************************/ + struct hsearch_data * hash_field_names; + + /***************************************************************************/ + /* Hash table containing nv_pair_field_name as keys, and */ + /* suppressed_nv_pairs_list as values. */ + /***************************************************************************/ + struct hsearch_data * hash_nv_pairs_list; + +} EVEL_THROTTLE_SPEC; + +/*****************************************************************************/ +/* RFC2822 format string for strftime. */ +/*****************************************************************************/ +#define EVEL_RFC2822_STRFTIME_FORMAT "%a, %d %b %Y %T %z" + +/*****************************************************************************/ +/* EVEL_JSON_BUFFER depth at which we throttle fields. */ +/*****************************************************************************/ +#define EVEL_THROTTLE_FIELD_DEPTH 3 + +/**************************************************************************//** + * Initialize the event handler. + * + * Primarily responsible for getting cURL ready for use. + * + * @param[in] event_api_url + * The URL where the Vendor Event Listener API is expected + * to be. + * @param[in] throt_api_url + * The URL where the Throttling API is expected to be. + * @param[in] username The username for the Basic Authentication of requests. + * @param[in] password The password for the Basic Authentication of requests. + * @param verbosity 0 for normal operation, positive values for chattier + * logs. + *****************************************************************************/ +EVEL_ERR_CODES event_handler_initialize(const char * const event_api_url, + const char * const throt_api_url, + const char * const username, + const char * const password, + int verbosity); + +/**************************************************************************//** + * Terminate the event handler. + * + * Shuts down the event handler thread in as clean a way as possible. Sets the + * global exit flag and then signals the thread to interrupt it since it's + * most likely waiting on the ring-buffer. + * + * Having achieved an orderly shutdown of the event handler thread, clean up + * the cURL library's resources cleanly. + * + * @return Status code. + * @retval ::EVEL_SUCCESS if everything OK. + * @retval One of ::EVEL_ERR_CODES if there was a problem. + *****************************************************************************/ +EVEL_ERR_CODES event_handler_terminate(); + +/**************************************************************************//** + * Run the event handler. + * + * Spawns the thread responsible for handling events and sending them to the + * API. + * + * @return Status code. + * @retval ::EVEL_SUCCESS if everything OK. + * @retval One of ::EVEL_ERR_CODES if there was a problem. + *****************************************************************************/ +EVEL_ERR_CODES event_handler_run(); + +/**************************************************************************//** + * Create a new internal event. + * + * @note The mandatory fields on the Fault must be supplied to this factory + * function and are immutable once set. Optional fields have explicit + * setter functions, but again values may only be set once so that the + * Fault has immutable properties. + * @param command The condition indicated by the event. + * @returns pointer to the newly manufactured ::EVENT_INTERNAL. If the event + * is not used (i.e. posted) it must be released using + * ::evel_free_event. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command); + +/**************************************************************************//** + * Free an internal event. + * + * Free off the event supplied. Will free all the contained* allocated memory. + * + * @note It does not free the internal event itself, since that may be part of + * a larger structure. + *****************************************************************************/ +void evel_free_internal_event(EVENT_INTERNAL * event); + +/**************************************************************************//** + * Initialize an event instance id, typically embedded in an event. + * + * @param instance_id Pointer to the event instance id being initialized. + * @param vendor_id The vendor id to encode in the event instance id. + * @param event_id The event id to encode in the event instance id. + *****************************************************************************/ +void evel_init_event_instance_id(EVEL_EVENT_INSTANCE_ID * const instance_id, + const char * const vendor_id, + const char * const event_id); + +/**************************************************************************//** + * Free an event instance id. + * + * @param instance_id Pointer to the event instance id being initialized. + *****************************************************************************/ +void evel_free_event_instance_id(EVEL_EVENT_INSTANCE_ID * const instance_id); + +/*****************************************************************************/ +/* Structure to hold JSON buffer and associated tracking, as it is written. */ +/*****************************************************************************/ +typedef struct evel_json_buffer +{ + char * json; + int offset; + int max_size; + + /***************************************************************************/ + /* The working throttle specification, which can be NULL. */ + /***************************************************************************/ + EVEL_THROTTLE_SPEC * throttle_spec; + + /***************************************************************************/ + /* Current object/list nesting depth. */ + /***************************************************************************/ + int depth; + + /***************************************************************************/ + /* The checkpoint. */ + /***************************************************************************/ + int checkpoint; + +} EVEL_JSON_BUFFER; + +/**************************************************************************//** + * Encode the event as a JSON event object according to AT&T's schema. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_header(EVEL_JSON_BUFFER * jbuf, + EVENT_HEADER * event); + +/**************************************************************************//** + * Encode the instance id as a JSON object according to AT&T's schema. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param instance_id Pointer to the ::EVEL_EVENT_INSTANCE_ID to encode. + *****************************************************************************/ +void evel_json_encode_instance_id(EVEL_JSON_BUFFER * jbuf, + EVEL_EVENT_INSTANCE_ID * instance_id); + +/**************************************************************************//** + * Encode the fault in JSON according to AT&T's schema for the fault type. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_fault(EVEL_JSON_BUFFER * jbuf, + EVENT_FAULT * event); + +/**************************************************************************//** + * Encode the measurement as a JSON measurement. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_measurement(EVEL_JSON_BUFFER * jbuf, + EVENT_MEASUREMENT * event); + +/**************************************************************************//** + * Encode the Mobile Flow in JSON according to AT&T's schema for the event + * type. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_mobile_flow(EVEL_JSON_BUFFER * jbuf, + EVENT_MOBILE_FLOW * event); + +/**************************************************************************//** + * Encode the report as a JSON report. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_report(EVEL_JSON_BUFFER * jbuf, + EVENT_REPORT * event); + +/**************************************************************************//** + * Encode the Service Event in JSON according to AT&T's schema for the event + * type. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_service(EVEL_JSON_BUFFER * const jbuf, + EVENT_SERVICE * const event); + +/**************************************************************************//** + * Encode the Signaling in JSON according to AT&T's schema for the event type. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_signaling(EVEL_JSON_BUFFER * const jbuf, + EVENT_SIGNALING * const event); + +/**************************************************************************//** + * Encode the state change as a JSON state change. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param state_change Pointer to the ::EVENT_STATE_CHANGE to encode. + *****************************************************************************/ +void evel_json_encode_state_change(EVEL_JSON_BUFFER * jbuf, + EVENT_STATE_CHANGE * state_change); + +/**************************************************************************//** + * Encode the Syslog in JSON according to AT&T's schema for the event type. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_syslog(EVEL_JSON_BUFFER * jbuf, + EVENT_SYSLOG * event); + +/**************************************************************************//** + * Encode the Other in JSON according to AT&T's schema for the event type. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_other(EVEL_JSON_BUFFER * jbuf, + EVENT_OTHER * event); + +/**************************************************************************//** + * Set the next event_sequence to use. + * + * @param sequence The next sequence number to use. + *****************************************************************************/ +void evel_set_next_event_sequence(const int sequence); + +/**************************************************************************//** + * Handle a JSON response from the listener, contained in a ::MEMORY_CHUNK. + * + * Tokenize the response, and decode any tokens found. + * + * @param chunk The memory chunk containing the response. + * @param post The memory chunk in which to place any resulting POST. + *****************************************************************************/ +void evel_handle_event_response(const MEMORY_CHUNK * const chunk, + MEMORY_CHUNK * const post); + +/**************************************************************************//** + * Initialize a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to initialise. + * @param json Pointer to the underlying working buffer to use. + * @param max_size Size of storage available in the JSON buffer. + * @param throttle_spec Pointer to throttle specification. Can be NULL. + *****************************************************************************/ +void evel_json_buffer_init(EVEL_JSON_BUFFER * jbuf, + char * const json, + const int max_size, + EVEL_THROTTLE_SPEC * throttle_spec); + +/**************************************************************************//** + * Encode a string key and string value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param option Pointer to holder of the corresponding value to encode. + * @return true if the key, value was added, false if it was suppressed. + *****************************************************************************/ +bool evel_enc_kv_opt_string(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const EVEL_OPTION_STRING * const option); + +/**************************************************************************//** + * Encode a string key and string value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param value Pointer to the corresponding value to encode. + *****************************************************************************/ +void evel_enc_kv_string(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const char * const value); + +/**************************************************************************//** + * Encode a string key and integer value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param option Pointer to holder of the corresponding value to encode. + * @return true if the key, value was added, false if it was suppressed. + *****************************************************************************/ +bool evel_enc_kv_opt_int(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const EVEL_OPTION_INT * const option); + +/**************************************************************************//** + * Encode a string key and integer value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param value The corresponding value to encode. + *****************************************************************************/ +void evel_enc_kv_int(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const int value); + +/**************************************************************************//** + * Encode a string key and double value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param option Pointer to holder of the corresponding value to encode. + * @return true if the key, value was added, false if it was suppressed. + *****************************************************************************/ +bool evel_enc_kv_opt_double(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const EVEL_OPTION_DOUBLE * const option); + +/**************************************************************************//** + * Encode a string key and double value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param value The corresponding value to encode. + *****************************************************************************/ +void evel_enc_kv_double(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const double value); + +/**************************************************************************//** + * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param option Pointer to holder of the corresponding value to encode. + * @return true if the key, value was added, false if it was suppressed. + *****************************************************************************/ +bool evel_enc_kv_opt_ull(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const EVEL_OPTION_ULL * const option); + +/**************************************************************************//** + * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param value The corresponding value to encode. + *****************************************************************************/ +void evel_enc_kv_ull(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const unsigned long long value); + +/**************************************************************************//** + * Encode a string key and time value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param option Pointer to holder of the corresponding value to encode. + * @return true if the key, value was added, false if it was suppressed. + *****************************************************************************/ +bool evel_enc_kv_opt_time(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const EVEL_OPTION_TIME * const option); + +/**************************************************************************//** + * Encode a string key and time value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param time Pointer to the time to encode. + *****************************************************************************/ +void evel_enc_kv_time(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const time_t * time); + +/**************************************************************************//** + * Encode a key and version. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param major_version The major version to encode. + * @param minor_version The minor version to encode. + *****************************************************************************/ +void evel_enc_version(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const int major_version, + const int minor_version); + +/**************************************************************************//** + * Add the key and opening bracket of an optional named list to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @return true if the list was opened, false if it was suppressed. + *****************************************************************************/ +bool evel_json_open_opt_named_list(EVEL_JSON_BUFFER * jbuf, + const char * const key); + +/**************************************************************************//** + * Add the key and opening bracket of a named list to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + *****************************************************************************/ +void evel_json_open_named_list(EVEL_JSON_BUFFER * jbuf, + const char * const key); + +/**************************************************************************//** + * Add the closing bracket of a list to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + *****************************************************************************/ +void evel_json_close_list(EVEL_JSON_BUFFER * jbuf); + +/**************************************************************************//** + * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param format Format string in standard printf format. + * @param ... Variable parameters for format string. + *****************************************************************************/ +void evel_enc_list_item(EVEL_JSON_BUFFER * jbuf, + const char * const format, + ...); + +/**************************************************************************//** + * Add the opening bracket of an optional named object to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + *****************************************************************************/ +bool evel_json_open_opt_named_object(EVEL_JSON_BUFFER * jbuf, + const char * const key); + +/**************************************************************************//** + * Add the opening bracket of an object to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @return true if the object was opened, false if it was suppressed. + *****************************************************************************/ +void evel_json_open_named_object(EVEL_JSON_BUFFER * jbuf, + const char * const key); + +/**************************************************************************//** + * Add the opening bracket of an object to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + *****************************************************************************/ +void evel_json_open_object(EVEL_JSON_BUFFER * jbuf); + +/**************************************************************************//** + * Add the closing bracket of an object to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + *****************************************************************************/ +void evel_json_close_object(EVEL_JSON_BUFFER * jbuf); + +/**************************************************************************//** + * Add a checkpoint - a stake in the ground to which we can rewind. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + *****************************************************************************/ +void evel_json_checkpoint(EVEL_JSON_BUFFER * jbuf); + +/**************************************************************************//** + * Rewind to the latest checkoint. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + *****************************************************************************/ +void evel_json_rewind(EVEL_JSON_BUFFER * jbuf); + +/**************************************************************************//** + * Free the underlying resources of an ::EVEL_OPTION_STRING. + * + * @param option Pointer to the ::EVEL_OPTION_STRING. + *****************************************************************************/ +void evel_free_option_string(EVEL_OPTION_STRING * const option); + +/**************************************************************************//** + * Initialize an ::EVEL_OPTION_STRING to a not-set state. + * + * @param option Pointer to the ::EVEL_OPTION_STRING. + *****************************************************************************/ +void evel_init_option_string(EVEL_OPTION_STRING * const option); + +/**************************************************************************//** + * Set the value of an ::EVEL_OPTION_STRING. + * + * @param option Pointer to the ::EVEL_OPTION_STRING. + * @param value The value to set. + * @param description Description to be used in logging. + *****************************************************************************/ +void evel_set_option_string(EVEL_OPTION_STRING * const option, + const char * const value, + const char * const description); + +/**************************************************************************//** + * Force the value of an ::EVEL_OPTION_STRING. + * + * @param option Pointer to the ::EVEL_OPTION_STRING. + * @param value The value to set. + *****************************************************************************/ +void evel_force_option_string(EVEL_OPTION_STRING * const option, + const char * const value); + +/**************************************************************************//** + * Initialize an ::EVEL_OPTION_INT to a not-set state. + * + * @param option Pointer to the ::EVEL_OPTION_INT. + *****************************************************************************/ +void evel_init_option_int(EVEL_OPTION_INT * const option); + +/**************************************************************************//** + * Force the value of an ::EVEL_OPTION_INT. + * + * @param option Pointer to the ::EVEL_OPTION_INT. + * @param value The value to set. + *****************************************************************************/ +void evel_force_option_int(EVEL_OPTION_INT * const option, + const int value); + +/**************************************************************************//** + * Set the value of an ::EVEL_OPTION_INT. + * + * @param option Pointer to the ::EVEL_OPTION_INT. + * @param value The value to set. + * @param description Description to be used in logging. + *****************************************************************************/ +void evel_set_option_int(EVEL_OPTION_INT * const option, + const int value, + const char * const description); + +/**************************************************************************//** + * Initialize an ::EVEL_OPTION_DOUBLE to a not-set state. + * + * @param option Pointer to the ::EVEL_OPTION_DOUBLE. + *****************************************************************************/ +void evel_init_option_double(EVEL_OPTION_DOUBLE * const option); + +/**************************************************************************//** + * Force the value of an ::EVEL_OPTION_DOUBLE. + * + * @param option Pointer to the ::EVEL_OPTION_DOUBLE. + * @param value The value to set. + *****************************************************************************/ +void evel_force_option_double(EVEL_OPTION_DOUBLE * const option, + const double value); + +/**************************************************************************//** + * Set the value of an ::EVEL_OPTION_DOUBLE. + * + * @param option Pointer to the ::EVEL_OPTION_DOUBLE. + * @param value The value to set. + * @param description Description to be used in logging. + *****************************************************************************/ +void evel_set_option_double(EVEL_OPTION_DOUBLE * const option, + const double value, + const char * const description); + +/**************************************************************************//** + * Initialize an ::EVEL_OPTION_ULL to a not-set state. + * + * @param option Pointer to the ::EVEL_OPTION_ULL. + *****************************************************************************/ +void evel_init_option_ull(EVEL_OPTION_ULL * const option); + +/**************************************************************************//** + * Force the value of an ::EVEL_OPTION_ULL. + * + * @param option Pointer to the ::EVEL_OPTION_ULL. + * @param value The value to set. + *****************************************************************************/ +void evel_force_option_ull(EVEL_OPTION_ULL * const option, + const unsigned long long value); + +/**************************************************************************//** + * Set the value of an ::EVEL_OPTION_ULL. + * + * @param option Pointer to the ::EVEL_OPTION_ULL. + * @param value The value to set. + * @param description Description to be used in logging. + *****************************************************************************/ +void evel_set_option_ull(EVEL_OPTION_ULL * const option, + const unsigned long long value, + const char * const description); + +/**************************************************************************//** + * Initialize an ::EVEL_OPTION_TIME to a not-set state. + * + * @param option Pointer to the ::EVEL_OPTION_TIME. + *****************************************************************************/ +void evel_init_option_time(EVEL_OPTION_TIME * const option); + +/**************************************************************************//** + * Force the value of an ::EVEL_OPTION_TIME. + * + * @param option Pointer to the ::EVEL_OPTION_TIME. + * @param value The value to set. + *****************************************************************************/ +void evel_force_option_time(EVEL_OPTION_TIME * const option, + const time_t value); + +/**************************************************************************//** + * Set the value of an ::EVEL_OPTION_TIME. + * + * @param option Pointer to the ::EVEL_OPTION_TIME. + * @param value The value to set. + * @param description Description to be used in logging. + *****************************************************************************/ +void evel_set_option_time(EVEL_OPTION_TIME * const option, + const time_t value, + const char * const description); + +/**************************************************************************//** + * Map an ::EVEL_COUNTER_CRITICALITIES enum value to the equivalent string. + * + * @param criticality The criticality to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_criticality(const EVEL_COUNTER_CRITICALITIES criticality); + +/**************************************************************************//** + * Map an ::EVEL_SEVERITIES enum value to the equivalent string. + * + * @param severity The severity to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_severity(const EVEL_SEVERITIES severity); + +/**************************************************************************//** + * Map an ::EVEL_ALERT_ACTIONS enum value to the equivalent string. + * + * @param alert_action The alert_action to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_alert_action(const EVEL_ALERT_ACTIONS alert_action); + +/**************************************************************************//** + * Map an ::EVEL_ALERT_TYPES enum value to the equivalent string. + * + * @param alert_type The alert_type to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_alert_type(const EVEL_ALERT_TYPES alert_type); + +/**************************************************************************//** + * Map an ::EVEL_EVENT_DOMAINS enum value to the equivalent string. + * + * @param domain The domain to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_event_domain(const EVEL_EVENT_DOMAINS domain); + +/**************************************************************************//** + * Map an ::EVEL_EVENT_PRIORITIES enum value to the equivalent string. + * + * @param priority The priority to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_event_priority(const EVEL_EVENT_PRIORITIES priority); + +/**************************************************************************//** + * Map an ::EVEL_SOURCE_TYPES enum value to the equivalent string. + * + * @param source_type The source type to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_source_type(const EVEL_SOURCE_TYPES source_type); + +/**************************************************************************//** + * Map an ::EVEL_VF_STATUSES enum value to the equivalent string. + * + * @param vf_status The vf_status to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_vf_status(const EVEL_VF_STATUSES vf_status); + +/**************************************************************************//** + * Convert a ::EVEL_ENTITY_STATE to it's string form for JSON encoding. + * + * @param state The entity state to encode. + * + * @returns the corresponding string + *****************************************************************************/ +char * evel_entity_state(const EVEL_ENTITY_STATE state); + +/**************************************************************************//** + * Convert a ::EVEL_SERVICE_ENDPOINT_DESC to string form for JSON encoding. + * + * @param endpoint_desc endpoint description to encode. + * + * @returns the corresponding string + *****************************************************************************/ +char * evel_service_endpoint_desc(const EVEL_ENTITY_STATE endpoint_desc); + +#endif diff --git a/vnfs/VES/code/evel_library/evel_internal_event.c b/vnfs/VES/code/evel_library/evel_internal_event.c new file mode 100644 index 00000000..03a3d14d --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_internal_event.c @@ -0,0 +1,124 @@ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the internal events. + * + * Internal events are never expected to be sent to the JSON API but comply + * with interfaces for regular event types. The primary use-case is to enable + * the foreground processing to communicate with the background event handling + * processing in an orderly fashion. At present the only use is to initiate an + * orderly shutdown of the Event Handler thread. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include + +#include "evel.h" +#include "evel_internal.h" + + +/**************************************************************************//** + * Create a new internal event. + * + * @note The mandatory fields on the Fault must be supplied to this factory + * function and are immutable once set. Optional fields have explicit + * setter functions, but again values may only be set once so that the + * Fault has immutable properties. + * @param command The condition indicated by the event. + * @returns pointer to the newly manufactured ::EVENT_INTERNAL. If the event + * is not used (i.e. posted) it must be released using + * ::evel_free_event. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command) +{ + EVENT_INTERNAL * event = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(command < EVT_CMD_MAX_COMMANDS); + + /***************************************************************************/ + /* Allocate the fault. */ + /***************************************************************************/ + event = malloc(sizeof(EVENT_INTERNAL)); + if (event == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(event, 0, sizeof(EVENT_INTERNAL)); + EVEL_DEBUG("New internal event is at %lp", event); + + /***************************************************************************/ + /* Initialize the header & the event fields. */ + /***************************************************************************/ + evel_init_header(&event->header); + event->header.event_domain = EVEL_DOMAIN_INTERNAL; + event->command = command; + +exit_label: + EVEL_EXIT(); + return event; +} + +/**************************************************************************//** + * Free an internal event. + * + * Free off the event supplied. Will free all the contained allocated memory. + * + * @note It does not free the internal event itself, since that may be part of + * a larger structure. + *****************************************************************************/ +void evel_free_internal_event(EVENT_INTERNAL * event) +{ + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the public API. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_INTERNAL); + + /***************************************************************************/ + /* Free the header itself. */ + /***************************************************************************/ + evel_free_header(&event->header); + + EVEL_EXIT(); +} \ No newline at end of file diff --git a/vnfs/VES/code/evel_library/evel_json_buffer.c b/vnfs/VES/code/evel_library/evel_json_buffer.c new file mode 100644 index 00000000..7ae3453b --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_json_buffer.c @@ -0,0 +1,853 @@ +/**************************************************************************//** + * @file + * Source module relating to internal EVEL_JSON_BUFFER manipulation functions. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include + +#include "evel_throttle.h" + +/*****************************************************************************/ +/* Local prototypes. */ +/*****************************************************************************/ +static char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf); + +/**************************************************************************//** + * Initialize a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to initialise. + * @param json Pointer to the underlying working buffer to use. + * @param max_size Size of storage available in the JSON buffer. + * @param throttle_spec Pointer to throttle specification. Can be NULL. + *****************************************************************************/ +void evel_json_buffer_init(EVEL_JSON_BUFFER * jbuf, + char * const json, + const int max_size, + EVEL_THROTTLE_SPEC * throttle_spec) +{ + EVEL_ENTER(); + + assert(jbuf != NULL); + assert(json != NULL); + jbuf->json = json; + jbuf->max_size = max_size; + jbuf->offset = 0; + jbuf->throttle_spec = throttle_spec; + jbuf->depth = 0; + jbuf->checkpoint = -1; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode an integer value to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param value The integer to add to it. + *****************************************************************************/ +void evel_enc_int(EVEL_JSON_BUFFER * jbuf, + const int value) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "%d", value); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode a string key and string value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param option Pointer to holder of the corresponding value to encode. + * @return true if the key, value was added, false if it was suppressed. + *****************************************************************************/ +bool evel_enc_kv_opt_string(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const EVEL_OPTION_STRING * const option) +{ + bool added = false; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + if (option->is_set) + { + if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) && + (jbuf->throttle_spec != NULL) && + evel_throttle_suppress_field(jbuf->throttle_spec, key)) + { + EVEL_INFO("Suppressed: %s, %s", key, option->value); + } + else + { + EVEL_DEBUG("Encoded: %s, %s", key, option->value); + evel_enc_kv_string(jbuf, key, option->value); + added = true; + } + } + + EVEL_EXIT(); + + return added; +} + +/**************************************************************************//** + * Encode a string key and string value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param value Pointer to the corresponding value to encode. + *****************************************************************************/ +void evel_enc_kv_string(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const char * const value) +{ + int index; + int length; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(key != NULL); + + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "%s\"%s\": \"", + evel_json_kv_comma(jbuf), + key); + + /***************************************************************************/ + /* We need to escape quotation marks and backslashes in the value. */ + /***************************************************************************/ + length = strlen(value); + + for (index = 0; index < length; index++) + { + /*************************************************************************/ + /* Drop out if no more space. */ + /*************************************************************************/ + if (jbuf->max_size - jbuf->offset < 2) + { + break; + } + + /*************************************************************************/ + /* Add an escape character if necessary, then write the character */ + /* itself. */ + /*************************************************************************/ + if ((value[index] == '\"') || (value[index] == '\\')) + { + jbuf->json[jbuf->offset] = '\\'; + jbuf->offset++; + } + + jbuf->json[jbuf->offset] = value[index]; + jbuf->offset++; + } + + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "\""); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode a string key and integer value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param option Pointer to holder of the corresponding value to encode. + * @return true if the key, value was added, false if it was suppressed. + *****************************************************************************/ +bool evel_enc_kv_opt_int(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const EVEL_OPTION_INT * const option) +{ + bool added = false; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + if (option->is_set) + { + if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) && + (jbuf->throttle_spec != NULL) && + evel_throttle_suppress_field(jbuf->throttle_spec, key)) + { + EVEL_INFO("Suppressed: %s, %d", key, option->value); + } + else + { + EVEL_DEBUG("Encoded: %s, %d", key, option->value); + evel_enc_kv_int(jbuf, key, option->value); + added = true; + } + } + + EVEL_EXIT(); + + return added; +} + +/**************************************************************************//** + * Encode a string key and integer value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param value The corresponding value to encode. + *****************************************************************************/ +void evel_enc_kv_int(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const int value) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(key != NULL); + + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "%s\"%s\": %d", + evel_json_kv_comma(jbuf), + key, + value); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode a string key and double value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param option Pointer to holder of the corresponding value to encode. + * @return true if the key, value was added, false if it was suppressed. + *****************************************************************************/ +bool evel_enc_kv_opt_double(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const EVEL_OPTION_DOUBLE * const option) +{ + bool added = false; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + if (option->is_set) + { + if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) && + (jbuf->throttle_spec != NULL) && + evel_throttle_suppress_field(jbuf->throttle_spec, key)) + { + EVEL_INFO("Suppressed: %s, %1f", key, option->value); + } + else + { + EVEL_DEBUG("Encoded: %s, %1f", key, option->value); + evel_enc_kv_double(jbuf, key, option->value); + added = true; + } + } + + EVEL_EXIT(); + + return added; +} + +/**************************************************************************//** + * Encode a string key and double value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param value The corresponding value to encode. + *****************************************************************************/ +void evel_enc_kv_double(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const double value) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(key != NULL); + + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "%s\"%s\": %1f", + evel_json_kv_comma(jbuf), + key, + value); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param option Pointer to holder of the corresponding value to encode. + * @return true if the key, value was added, false if it was suppressed. + *****************************************************************************/ +bool evel_enc_kv_opt_ull(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const EVEL_OPTION_ULL * const option) +{ + bool added = false; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + if (option->is_set) + { + if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) && + (jbuf->throttle_spec != NULL) && + evel_throttle_suppress_field(jbuf->throttle_spec, key)) + { + EVEL_INFO("Suppressed: %s, %1lu", key, option->value); + } + else + { + EVEL_DEBUG("Encoded: %s, %1lu", key, option->value); + evel_enc_kv_ull(jbuf, key, option->value); + added = true; + } + } + + EVEL_EXIT(); + + return added; +} + +/**************************************************************************//** + * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param value The corresponding value to encode. + *****************************************************************************/ +void evel_enc_kv_ull(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const unsigned long long value) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(key != NULL); + + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "%s\"%s\": %llu", + evel_json_kv_comma(jbuf), + key, + value); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode a string key and time value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param option Pointer to holder of the corresponding value to encode. + * @return true if the key, value was added, false if it was suppressed. + *****************************************************************************/ +bool evel_enc_kv_opt_time(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const EVEL_OPTION_TIME * const option) +{ + bool added = false; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + if (option->is_set) + { + if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) && + (jbuf->throttle_spec != NULL) && + evel_throttle_suppress_field(jbuf->throttle_spec, key)) + { + EVEL_INFO("Suppressed time: %s", key); + } + else + { + EVEL_DEBUG("Encoded time: %s", key); + evel_enc_kv_time(jbuf, key, &option->value); + added = true; + } + } + + EVEL_EXIT(); + + return added; +} + +/**************************************************************************//** + * Encode a string key and time value to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param time Pointer to the time to encode. + *****************************************************************************/ +void evel_enc_kv_time(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const time_t * time) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(key != NULL); + assert(time != NULL); + + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "%s\"%s\": \"", + evel_json_kv_comma(jbuf), + key); + jbuf->offset += strftime(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + EVEL_RFC2822_STRFTIME_FORMAT, + localtime(time)); + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "\""); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode a key and version. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @param major_version The major version to encode. + * @param minor_version The minor version to encode. + *****************************************************************************/ +void evel_enc_version(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const int major_version, + const int minor_version) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(key != NULL); + + evel_enc_kv_int(jbuf, key, major_version); + if (minor_version != 0) + { + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + ".%d", + minor_version); + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add the key and opening bracket of an optional named list to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @return true if the list was opened, false if it was suppressed. + *****************************************************************************/ +bool evel_json_open_opt_named_list(EVEL_JSON_BUFFER * jbuf, + const char * const key) +{ + bool opened = false; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(key != NULL); + + if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) && + (jbuf->throttle_spec != NULL) && + evel_throttle_suppress_field(jbuf->throttle_spec, key)) + { + EVEL_INFO("Suppressed: %s", key); + opened = false; + } + else + { + evel_json_open_named_list(jbuf, key); + opened = true; + } + + EVEL_EXIT(); + + return opened; +} + +/**************************************************************************//** + * Add the key and opening bracket of a named list to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + *****************************************************************************/ +void evel_json_open_named_list(EVEL_JSON_BUFFER * jbuf, + const char * const key) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(key != NULL); + + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "%s\"%s\": [", + evel_json_kv_comma(jbuf), + key); + jbuf->depth++; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add the closing bracket of a list to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + *****************************************************************************/ +void evel_json_close_list(EVEL_JSON_BUFFER * jbuf) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "]"); + jbuf->depth--; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param format Format string in standard printf format. + * @param ... Variable parameters for format string. + *****************************************************************************/ +void evel_enc_list_item(EVEL_JSON_BUFFER * jbuf, + const char * const format, + ...) +{ + va_list largs; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(format != NULL); + + /***************************************************************************/ + /* Add a comma unless we're at the start of the list. */ + /***************************************************************************/ + if (jbuf->json[jbuf->offset - 1] != '[') + { + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + ", "); + } + + va_start(largs, format); + jbuf->offset += vsnprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + format, + largs); + va_end(largs); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add the opening bracket of an optional named object to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + *****************************************************************************/ +bool evel_json_open_opt_named_object(EVEL_JSON_BUFFER * jbuf, + const char * const key) +{ + bool opened = false; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(key != NULL); + + if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) && + (jbuf->throttle_spec != NULL) && + evel_throttle_suppress_field(jbuf->throttle_spec, key)) + { + EVEL_INFO("Suppressed: %s", key); + opened = false; + } + else + { + evel_json_open_named_object(jbuf, key); + opened = true; + } + + EVEL_EXIT(); + + return opened; +} + +/**************************************************************************//** + * Add the opening bracket of an object to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param key Pointer to the key to encode. + * @return true if the object was opened, false if it was suppressed. + *****************************************************************************/ +void evel_json_open_named_object(EVEL_JSON_BUFFER * jbuf, + const char * const key) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(key != NULL); + + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "%s\"%s\": {", + evel_json_kv_comma(jbuf), + key); + jbuf->depth++; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add the opening bracket of an object to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + *****************************************************************************/ +void evel_json_open_object(EVEL_JSON_BUFFER * jbuf) +{ + char * comma; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + + if ((jbuf->offset != 0) && (jbuf->json[jbuf->offset-1] == '}')) + { + comma = ", "; + } + else + { + comma = ""; + } + + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "%s{", + comma); + jbuf->depth++; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add the closing bracket of an object to a JSON buffer. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + *****************************************************************************/ +void evel_json_close_object(EVEL_JSON_BUFFER * jbuf) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + + jbuf->offset += snprintf(jbuf->json + jbuf->offset, + jbuf->max_size - jbuf->offset, + "}"); + jbuf->depth--; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Determine whether to add a comma when adding a key-value pair. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @returns A string containing the comma if it is required. + *****************************************************************************/ +char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf) +{ + char * result; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + + if ((jbuf->offset == 0) || + (jbuf->json[jbuf->offset-1] == '{') || + (jbuf->json[jbuf->offset-1] == '[')) + { + result = ""; + } + else + { + result = ", "; + } + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Add a checkpoint - a stake in the ground to which we can rewind. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + *****************************************************************************/ +void evel_json_checkpoint(EVEL_JSON_BUFFER * jbuf) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + + /***************************************************************************/ + /* Store the current offset. */ + /***************************************************************************/ + jbuf->checkpoint = jbuf->offset; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Rewind to the latest checkoint. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + *****************************************************************************/ +void evel_json_rewind(EVEL_JSON_BUFFER * jbuf) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(jbuf->checkpoint >= 0); + assert(jbuf->checkpoint <= jbuf->offset); + + /***************************************************************************/ + /* Reinstate the offset from the last checkpoint. */ + /***************************************************************************/ + jbuf->offset = jbuf->checkpoint; + jbuf->checkpoint = -1; + + EVEL_EXIT(); +} diff --git a/vnfs/VES/code/evel_library/evel_logging.c b/vnfs/VES/code/evel_library/evel_logging.c new file mode 100644 index 00000000..6dabc638 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_logging.c @@ -0,0 +1,181 @@ +/**************************************************************************//** + * @file + * Wrapper for event logging built on syslog. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include +#include +#include + +#include + +#include "evel.h" + + +/*****************************************************************************/ +/* Debug settings. Logging is done through macros so these need to be */ +/* externally visible. */ +/*****************************************************************************/ +EVEL_LOG_LEVELS debug_level = EVEL_LOG_DEBUG; +//static char *syslog_ident = "evel"; +int debug_indent = 0; + +/*****************************************************************************/ +/* Buffers for error strings from this library. */ +/*****************************************************************************/ +static char evel_err_string[EVEL_MAX_ERROR_STRING_LEN] = ""; + + +/**************************************************************************//** + * Initialize logging + * + * @param[in] level The debugging level - one of ::EVEL_LOG_LEVELS. + * @param[in] ident The identifier for our logs. + *****************************************************************************/ +void log_initialize(EVEL_LOG_LEVELS level, const char * ident) +{ + assert(level < EVEL_LOG_MAX); + assert(ident != NULL); + + debug_level = level; + openlog(ident, LOG_PID, LOG_USER); +} + +/**************************************************************************//** + * Descriptive text for library errors. + * + * Return a text error string that relates to the last failure. May be + * "" but will never be NULL. + * + * @returns Text error string. + * + * @note Must not be freed! + *****************************************************************************/ +const char * evel_error_string(void) +{ + return(evel_err_string); +} + +/***************************************************************************//* + * Store the formatted string into the static error string and log the error. + * + * @param format Error string in standard printf format. + * @param ... Variable parameters to be substituted into the format string. + *****************************************************************************/ +void log_error_state(char * format, ...) +{ + va_list largs; + + assert(format != NULL); + va_start(largs, format); + vsnprintf(evel_err_string, EVEL_MAX_ERROR_STRING_LEN, format, largs); + va_end(largs); + EVEL_ERROR("%s", evel_err_string); +} + + +/**************************************************************************//** + * Generate a debug log. + * + * Provides an interface to syslog with formatting of the nesting level + * so that it's easier to see function entry/exit. + * + * @param[in] level The debug level - see ::EVEL_LOG_LEVELS. + * @param[in] format The output formatting in printf style. + * @param[in] ... Variable arguments as specified in the format string. + *****************************************************************************/ +void log_debug(EVEL_LOG_LEVELS level, char * format, ...) +{ + va_list largs; + int priority; + char indent_fmt[1024]; + char *syslog_fmt = NULL; + + /***************************************************************************/ + /* Test assumptions. */ + /***************************************************************************/ + assert(format != NULL); + assert(level <= EVEL_LOG_MAX); + + if (level >= debug_level) + { + if ((debug_level == EVEL_LOG_INFO) || (debug_indent == 0)) + { + /***********************************************************************/ + /* Just use the format as is. */ + /***********************************************************************/ + syslog_fmt = format; + } + else + { + /***********************************************************************/ + /* Combine the format with a preceding number of indent markers. */ + /***********************************************************************/ + sprintf(indent_fmt, "%.*s%s", + debug_indent, + INDENT_SEPARATORS, + format); + syslog_fmt = indent_fmt; + } + + /*************************************************************************/ + /* Work out the syslog priority value. */ + /*************************************************************************/ + switch (level) + { + case EVEL_LOG_ERROR: + priority = LOG_ERR; + break; + + case EVEL_LOG_INFO: + priority = LOG_INFO; + break; + + case EVEL_LOG_DEBUG: + case EVEL_LOG_SPAMMY: + default: + priority = LOG_DEBUG; + break; + } + + /*************************************************************************/ + /* Write the log to the file next, which requires the var args list. */ + /*************************************************************************/ + va_start(largs, format); + vsyslog(priority, syslog_fmt, largs); + va_end(largs); + } +} \ No newline at end of file diff --git a/vnfs/VES/code/evel_library/evel_mobile_flow.c b/vnfs/VES/code/evel_library/evel_mobile_flow.c new file mode 100644 index 00000000..45f22ea7 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_mobile_flow.c @@ -0,0 +1,2036 @@ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the Mobile Flow. + * + * License + * ------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include +#include + +#include "evel.h" +#include "evel_internal.h" + +/*****************************************************************************/ +/* Array of strings to use when encoding TCP flags. */ +/*****************************************************************************/ +static char * evel_tcp_flag_strings[EVEL_MAX_TCP_FLAGS] = { + "NS", + "CWR", + "ECE", + "URG", + "ACK", + "PSH", + "RST", + "SYN", + "FIN" +}; + +/*****************************************************************************/ +/* Array of strings to use when encoding QCI COS. */ +/*****************************************************************************/ +static char * evel_qci_cos_strings[EVEL_MAX_QCI_COS_TYPES] = { + "conversational", + "streaming", + "interactive", + "background", + "1", + "2", + "3", + "4", + "65", + "66", + "5", + "6", + "7", + "8", + "9", + "69", + "70" +}; + +/*****************************************************************************/ +/* Local prototypes */ +/*****************************************************************************/ +void evel_json_encode_mobile_flow_gtp_flow_metrics( + EVEL_JSON_BUFFER * jbuf, + MOBILE_GTP_PER_FLOW_METRICS * metrics); + +/**************************************************************************//** + * Create a new Mobile Flow event. + * + * @note The mandatory fields on the Mobile Flow must be supplied to this + * factory function and are immutable once set. Optional fields have + * explicit setter functions, but again values may only be set once so + * that the Mobile Flow has immutable properties. + * @param flow_direction Flow direction. + * @param gtp_per_flow_metrics GTP per-flow metrics. + * @param ip_protocol_type IP protocol type. + * @param ip_version IP protocol version. + * @param other_endpoint_ip_address IP address of the other endpoint. + * @param other_endpoint_port IP port of the other endpoint. + * @param reporting_endpoint_ip_addr IP address of the reporting endpoint. + * @param reporting_endpoint_port IP port of the reporting endpoint. + * @returns pointer to the newly manufactured ::EVENT_MOBILE_FLOW. If the + * event is not used (i.e. posted) it must be released using + * ::evel_free_mobile_flow. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_MOBILE_FLOW * evel_new_mobile_flow( + const char * const flow_direction, + MOBILE_GTP_PER_FLOW_METRICS * gtp_per_flow_metrics, + const char * const ip_protocol_type, + const char * const ip_version, + const char * const other_endpoint_ip_address, + int other_endpoint_port, + const char * const reporting_endpoint_ip_addr, + int reporting_endpoint_port) +{ + EVENT_MOBILE_FLOW * mobile_flow = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(flow_direction != NULL); + assert(gtp_per_flow_metrics != NULL); + assert(ip_protocol_type != NULL); + assert(ip_version != NULL); + assert(other_endpoint_ip_address != NULL); + assert(other_endpoint_port > 0); + assert(reporting_endpoint_ip_addr != NULL); + assert(reporting_endpoint_port > 0); + + /***************************************************************************/ + /* Allocate the Mobile Flow. */ + /***************************************************************************/ + mobile_flow = malloc(sizeof(EVENT_MOBILE_FLOW)); + if (mobile_flow == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(mobile_flow, 0, sizeof(EVENT_MOBILE_FLOW)); + EVEL_DEBUG("New Mobile Flow is at %lp", mobile_flow); + + /***************************************************************************/ + /* Initialize the header & the Mobile Flow fields. Optional string values */ + /* are uninitialized (NULL). */ + /***************************************************************************/ + evel_init_header(&mobile_flow->header); + mobile_flow->header.event_domain = EVEL_DOMAIN_MOBILE_FLOW; + mobile_flow->major_version = EVEL_MOBILE_FLOW_MAJOR_VERSION; + mobile_flow->minor_version = EVEL_MOBILE_FLOW_MINOR_VERSION; + mobile_flow->flow_direction = strdup(flow_direction); + mobile_flow->gtp_per_flow_metrics = gtp_per_flow_metrics; + mobile_flow->ip_protocol_type = strdup(ip_protocol_type); + mobile_flow->ip_version = strdup(ip_version); + mobile_flow->other_endpoint_ip_address = strdup(other_endpoint_ip_address); + mobile_flow->other_endpoint_port = other_endpoint_port; + mobile_flow->reporting_endpoint_ip_addr = strdup(reporting_endpoint_ip_addr); + mobile_flow->reporting_endpoint_port = reporting_endpoint_port; + evel_init_option_string(&mobile_flow->application_type); + evel_init_option_string(&mobile_flow->app_protocol_type); + evel_init_option_string(&mobile_flow->app_protocol_version); + evel_init_option_string(&mobile_flow->cid); + evel_init_option_string(&mobile_flow->connection_type); + evel_init_option_string(&mobile_flow->ecgi); + evel_init_option_string(&mobile_flow->gtp_protocol_type); + evel_init_option_string(&mobile_flow->gtp_version); + evel_init_option_string(&mobile_flow->http_header); + evel_init_option_string(&mobile_flow->imei); + evel_init_option_string(&mobile_flow->imsi); + evel_init_option_string(&mobile_flow->lac); + evel_init_option_string(&mobile_flow->mcc); + evel_init_option_string(&mobile_flow->mnc); + evel_init_option_string(&mobile_flow->msisdn); + evel_init_option_string(&mobile_flow->other_functional_role); + evel_init_option_string(&mobile_flow->rac); + evel_init_option_string(&mobile_flow->radio_access_technology); + evel_init_option_string(&mobile_flow->sac); + evel_init_option_int(&mobile_flow->sampling_algorithm); + evel_init_option_string(&mobile_flow->tac); + evel_init_option_string(&mobile_flow->tunnel_id); + evel_init_option_string(&mobile_flow->vlan_id); + +exit_label: + EVEL_EXIT(); + return mobile_flow; +} + +/**************************************************************************//** + * Set the Event Type property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_mobile_flow_type_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + evel_header_type_set(&mobile_flow->header, type); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Application Type property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param type The Application Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_mobile_flow_app_type_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(type != NULL); + + evel_set_option_string(&mobile_flow->application_type, + type, + "Application Type"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Application Protocol Type property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param type The Application Protocol Type to be set. ASCIIZ string. + * The caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_flow_app_prot_type_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(type != NULL); + + evel_set_option_string(&mobile_flow->app_protocol_type, + type, + "Application Protocol Type"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Application Protocol Version property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param version The Application Protocol Version to be set. ASCIIZ + * string. The caller does not need to preserve the value + * once the function returns. + *****************************************************************************/ +void evel_mobile_flow_app_prot_ver_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const version) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(version != NULL); + + evel_set_option_string(&mobile_flow->app_protocol_version, + version, + "Application Protocol Version"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the CID property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param cid The CID to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_cid_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const cid) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(cid != NULL); + + evel_set_option_string(&mobile_flow->cid, + cid, + "CID"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Connection Type property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param type The Connection Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_mobile_flow_con_type_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(type != NULL); + + evel_set_option_string(&mobile_flow->connection_type, + type, + "Connection Type"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the ECGI property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param ecgi The ECGI to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_ecgi_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const ecgi) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(ecgi != NULL); + + evel_set_option_string(&mobile_flow->ecgi, + ecgi, + "ECGI"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the GTP Protocol Type property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param type The GTP Protocol Type to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_flow_gtp_prot_type_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(type != NULL); + + evel_set_option_string(&mobile_flow->gtp_protocol_type, + type, + "GTP Protocol Type"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the GTP Protocol Version property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param version The GTP Protocol Version to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_flow_gtp_prot_ver_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const version) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(version != NULL); + + evel_set_option_string(&mobile_flow->gtp_version, + version, + "GTP Protocol Version"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the HTTP Header property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param header The HTTP header to be set. ASCIIZ string. The caller does + * not need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_http_header_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const header) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(header != NULL); + + evel_set_option_string(&mobile_flow->http_header, + header, + "HTTP Header"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the IMEI property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param imei The IMEI to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_imei_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const imei) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(imei != NULL); + + evel_set_option_string(&mobile_flow->imei, + imei, + "IMEI"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the IMSI property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param imsi The IMSI to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_imsi_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const imsi) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(imsi != NULL); + + evel_set_option_string(&mobile_flow->imsi, + imsi, + "IMSI"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the LAC property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param lac The LAC to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_lac_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const lac) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(lac != NULL); + + evel_set_option_string(&mobile_flow->lac, + lac, + "LAC"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the MCC property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param mcc The MCC to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_mcc_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const mcc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(mcc != NULL); + + evel_set_option_string(&mobile_flow->mcc, + mcc, + "MCC"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the MNC property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param mnc The MNC to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_mnc_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const mnc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(mnc != NULL); + + evel_set_option_string(&mobile_flow->mnc, + mnc, + "MNC"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the MSISDN property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param msisdn The MSISDN to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_msisdn_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const msisdn) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(msisdn != NULL); + + evel_set_option_string(&mobile_flow->msisdn, + msisdn, + "MSISDN"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Other Functional Role property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param role The Other Functional Role to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_flow_other_func_role_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const role) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(role != NULL); + + evel_set_option_string(&mobile_flow->other_functional_role, + role, + "Other Functional Role"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the RAC property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param rac The RAC to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_rac_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const rac) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(rac != NULL); + + evel_set_option_string(&mobile_flow->rac, + rac, + "RAC"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Radio Access Technology property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param tech The Radio Access Technology to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_flow_radio_acc_tech_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const tech) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(tech != NULL); + + evel_set_option_string(&mobile_flow->radio_access_technology, + tech, + "Radio Access Technology"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the SAC property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param sac The SAC to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_sac_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const sac) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(sac != NULL); + + evel_set_option_string(&mobile_flow->sac, + sac, + "SAC"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Sampling Algorithm property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param algorithm The Sampling Algorithm to be set. + *****************************************************************************/ +void evel_mobile_flow_samp_alg_set(EVENT_MOBILE_FLOW * mobile_flow, + int algorithm) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(algorithm >= 0); + + evel_set_option_int(&mobile_flow->sampling_algorithm, + algorithm, + "Sampling Algorithm"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the TAC property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param tac The TAC to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_tac_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const tac) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(tac != NULL); + + evel_set_option_string(&mobile_flow->tac, + tac, + "TAC"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Tunnel ID property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param tunnel_id The Tunnel ID to be set. ASCIIZ string. The caller does + * not need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_tunnel_id_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const tunnel_id) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(tunnel_id != NULL); + + evel_set_option_string(&mobile_flow->tunnel_id, + tunnel_id, + "Tunnel ID"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the VLAN ID property of the Mobile Flow. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param mobile_flow Pointer to the Mobile Flow. + * @param vlan_id The VLAN ID to be set. ASCIIZ string. The caller does + * not need to preserve the value once the function returns. + *****************************************************************************/ +void evel_mobile_flow_vlan_id_set(EVENT_MOBILE_FLOW * mobile_flow, + const char * const vlan_id) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(mobile_flow != NULL); + assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + assert(vlan_id != NULL); + + evel_set_option_string(&mobile_flow->vlan_id, + vlan_id, + "VLAN ID"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the Mobile Flow in JSON according to AT&T's schema for the event + * type. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_mobile_flow(EVEL_JSON_BUFFER * jbuf, + EVENT_MOBILE_FLOW * event) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + + evel_json_encode_header(jbuf, &event->header); + evel_json_open_named_object(jbuf, "mobileFlowFields"); + + /***************************************************************************/ + /* Mandatory parameters. */ + /***************************************************************************/ + evel_enc_kv_string(jbuf, "flowDirection", event->flow_direction); + evel_json_encode_mobile_flow_gtp_flow_metrics( + jbuf, event->gtp_per_flow_metrics); + evel_enc_kv_string(jbuf, "ipProtocolType", event->ip_protocol_type); + evel_enc_kv_string(jbuf, "ipVersion", event->ip_version); + evel_enc_kv_string( + jbuf, "otherEndpointIpAddress", event->other_endpoint_ip_address); + evel_enc_kv_int(jbuf, "otherEndpointPort", event->other_endpoint_port); + evel_enc_kv_string( + jbuf, "reportingEndpointIpAddr", event->reporting_endpoint_ip_addr); + evel_enc_kv_int( + jbuf, "reportingEndpointPort", event->reporting_endpoint_port); + + /***************************************************************************/ + /* Optional parameters. */ + /***************************************************************************/ + evel_enc_kv_opt_string(jbuf, "applicationType", &event->application_type); + evel_enc_kv_opt_string(jbuf, "appProtocolType", &event->app_protocol_type); + evel_enc_kv_opt_string( + jbuf, "appProtocolVersion", &event->app_protocol_version); + evel_enc_kv_opt_string(jbuf, "cid", &event->cid); + evel_enc_kv_opt_string(jbuf, "connectionType", &event->connection_type); + evel_enc_kv_opt_string(jbuf, "ecgi", &event->ecgi); + evel_enc_kv_opt_string(jbuf, "gtpProtocolType", &event->gtp_protocol_type); + evel_enc_kv_opt_string(jbuf, "gtpVersion", &event->gtp_version); + evel_enc_kv_opt_string(jbuf, "httpHeader", &event->http_header); + evel_enc_kv_opt_string(jbuf, "imei", &event->imei); + evel_enc_kv_opt_string(jbuf, "imsi", &event->imsi); + evel_enc_kv_opt_string(jbuf, "lac", &event->lac); + evel_enc_kv_opt_string(jbuf, "mcc", &event->mcc); + evel_enc_kv_opt_string(jbuf, "mnc", &event->mnc); + evel_enc_kv_opt_string(jbuf, "msisdn", &event->msisdn); + evel_enc_kv_opt_string( + jbuf, "otherFunctionalRole", &event->other_functional_role); + evel_enc_kv_opt_string(jbuf, "rac", &event->rac); + evel_enc_kv_opt_string( + jbuf, "radioAccessTechnology", &event->radio_access_technology); + evel_enc_kv_opt_string(jbuf, "sac", &event->sac); + evel_enc_kv_opt_int(jbuf, "samplingAlgorithm", &event->sampling_algorithm); + evel_enc_kv_opt_string(jbuf, "tac", &event->tac); + evel_enc_kv_opt_string(jbuf, "tunnelId", &event->tunnel_id); + evel_enc_kv_opt_string(jbuf, "vlanId", &event->vlan_id); +#if 0 + /***************************************************************************/ + /* Not in schema. */ + /***************************************************************************/ + evel_enc_version(jbuf, + "mobileFlowFieldsVersion", + event->major_version, + event->minor_version); +#endif + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free a Mobile Flow. + * + * Free off the Mobile Flow supplied. Will free all the contained allocated + * memory. + * + * @note It does not free the Mobile Flow itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_mobile_flow(EVENT_MOBILE_FLOW * event) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the public API. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + + /***************************************************************************/ + /* Free all internal strings then the header itself. */ + /***************************************************************************/ + free(event->flow_direction); + + evel_free_mobile_gtp_flow_metrics(event->gtp_per_flow_metrics); + free(event->gtp_per_flow_metrics); + free(event->ip_protocol_type); + free(event->ip_version); + free(event->other_endpoint_ip_address); + free(event->reporting_endpoint_ip_addr); + evel_free_option_string(&event->application_type); + evel_free_option_string(&event->app_protocol_type); + evel_free_option_string(&event->app_protocol_version); + evel_free_option_string(&event->cid); + evel_free_option_string(&event->connection_type); + evel_free_option_string(&event->ecgi); + evel_free_option_string(&event->gtp_protocol_type); + evel_free_option_string(&event->gtp_version); + evel_free_option_string(&event->http_header); + evel_free_option_string(&event->imei); + evel_free_option_string(&event->imsi); + evel_free_option_string(&event->lac); + evel_free_option_string(&event->mcc); + evel_free_option_string(&event->mnc); + evel_free_option_string(&event->msisdn); + evel_free_option_string(&event->other_functional_role); + evel_free_option_string(&event->rac); + evel_free_option_string(&event->radio_access_technology); + evel_free_option_string(&event->sac); + evel_free_option_string(&event->tac); + evel_free_option_string(&event->tunnel_id); + evel_free_option_string(&event->vlan_id); + + evel_free_header(&event->header); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Create a new Mobile GTP Per Flow Metrics. + * + * @note The mandatory fields on the Mobile GTP Per Flow Metrics must be + * supplied to this factory function and are immutable once set. + * Optional fields have explicit setter functions, but again values + * may only be set once so that the Mobile GTP Per Flow Metrics has + * immutable properties. + * + * @param avg_bit_error_rate Average bit error rate. + * @param avg_packet_delay_variation Average delay or jitter in ms. + * @param avg_packet_latency Average delivery latency. + * @param avg_receive_throughput Average receive throughput. + * @param avg_transmit_throughput Average transmit throughput. + * @param flow_activation_epoch Time the connection is activated. + * @param flow_activation_microsec Microseconds for the start of the flow + * connection. + * @param flow_deactivation_epoch Time for the end of the connection. + * @param flow_deactivation_microsec Microseconds for the end of the flow + * connection. + * @param flow_deactivation_time Transmission time of the first packet. + * @param flow_status Connection status. + * @param max_packet_delay_variation Maximum packet delay or jitter in ms. + * @param num_activation_failures Number of failed activation requests. + * @param num_bit_errors Number of errored bits. + * @param num_bytes_received Number of bytes received. + * @param num_bytes_transmitted Number of bytes transmitted. + * @param num_dropped_packets Number of received packets dropped. + * @param num_l7_bytes_received Number of tunneled Layer 7 bytes + * received. + * @param num_l7_bytes_transmitted Number of tunneled Layer 7 bytes + * transmitted. + * @param num_lost_packets Number of lost packets. + * @param num_out_of_order_packets Number of out-of-order packets. + * @param num_packet_errors Number of errored packets. + * @param num_packets_received_excl_retrans Number of packets received, + * excluding retransmits. + * @param num_packets_received_incl_retrans Number of packets received. + * @param num_packets_transmitted_incl_retrans Number of packets + * transmitted. + * @param num_retries Number of packet retries. + * @param num_timeouts Number of packet timeouts. + * @param num_tunneled_l7_bytes_received Number of tunneled Layer 7 bytes + * received, excluding retransmits. + * @param round_trip_time Round trip time. + * @param time_to_first_byte Time in ms between connection + * activation and first byte received. + * + * @returns pointer to the newly manufactured ::MOBILE_GTP_PER_FLOW_METRICS. + * If the structure is not used it must be released using + * ::evel_free_mobile_gtp_flow_metrics. + * @retval NULL Failed to create the event. + *****************************************************************************/ +MOBILE_GTP_PER_FLOW_METRICS * evel_new_mobile_gtp_flow_metrics( + double avg_bit_error_rate, + double avg_packet_delay_variation, + int avg_packet_latency, + int avg_receive_throughput, + int avg_transmit_throughput, + int flow_activation_epoch, + int flow_activation_microsec, + int flow_deactivation_epoch, + int flow_deactivation_microsec, + time_t flow_deactivation_time, + const char * const flow_status, + int max_packet_delay_variation, + int num_activation_failures, + int num_bit_errors, + int num_bytes_received, + int num_bytes_transmitted, + int num_dropped_packets, + int num_l7_bytes_received, + int num_l7_bytes_transmitted, + int num_lost_packets, + int num_out_of_order_packets, + int num_packet_errors, + int num_packets_received_excl_retrans, + int num_packets_received_incl_retrans, + int num_packets_transmitted_incl_retrans, + int num_retries, + int num_timeouts, + int num_tunneled_l7_bytes_received, + int round_trip_time, + int time_to_first_byte) +{ + MOBILE_GTP_PER_FLOW_METRICS * metrics = NULL; + int ii; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(avg_bit_error_rate >= 0.0); + assert(avg_packet_delay_variation >= 0.0); + assert(avg_packet_latency >= 0); + assert(avg_receive_throughput >= 0); + assert(avg_transmit_throughput >= 0); + assert(flow_activation_epoch > 0); + assert(flow_activation_microsec >= 0); + assert(flow_deactivation_epoch > 0); + assert(flow_deactivation_microsec >= 0); + assert(flow_status != NULL); + assert(max_packet_delay_variation >= 0); + assert(num_activation_failures >= 0); + assert(num_bit_errors >= 0); + assert(num_bytes_received >= 0); + assert(num_bytes_transmitted >= 0); + assert(num_dropped_packets >= 0); + assert(num_l7_bytes_received >= 0); + assert(num_l7_bytes_transmitted >= 0); + assert(num_lost_packets >= 0); + assert(num_out_of_order_packets >= 0); + assert(num_packet_errors >= 0); + assert(num_packets_received_excl_retrans >= 0); + assert(num_packets_received_incl_retrans >= 0); + assert(num_packets_transmitted_incl_retrans >= 0); + assert(num_retries >= 0); + assert(num_timeouts >= 0); + assert(num_tunneled_l7_bytes_received >= 0); + assert(round_trip_time >= 0); + assert(time_to_first_byte >= 0); + + /***************************************************************************/ + /* Allocate the Mobile Flow GTP Per Flow Metrics. */ + /***************************************************************************/ + metrics = malloc(sizeof(MOBILE_GTP_PER_FLOW_METRICS)); + if (metrics == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(metrics, 0, sizeof(MOBILE_GTP_PER_FLOW_METRICS)); + EVEL_DEBUG("New Mobile Flow GTP Per Flow Metrics is at %lp", metrics); + + /***************************************************************************/ + /* Initialize the Mobile Flow GTP Per Flow Metrics fields. Optional */ + /* string values are uninitialized (NULL). */ + /***************************************************************************/ + metrics->avg_bit_error_rate = avg_bit_error_rate; + metrics->avg_packet_delay_variation = avg_packet_delay_variation; + metrics->avg_packet_latency = avg_packet_latency; + metrics->avg_receive_throughput = avg_receive_throughput; + metrics->avg_transmit_throughput = avg_transmit_throughput; + metrics->flow_activation_epoch = flow_activation_epoch; + metrics->flow_activation_microsec = flow_activation_microsec; + metrics->flow_deactivation_epoch = flow_deactivation_epoch; + metrics->flow_deactivation_microsec = flow_deactivation_microsec; + metrics->flow_deactivation_time = flow_deactivation_time; + metrics->flow_status = strdup(flow_status); + metrics->max_packet_delay_variation = max_packet_delay_variation; + metrics->num_activation_failures = num_activation_failures; + metrics->num_bit_errors = num_bit_errors; + metrics->num_bytes_received = num_bytes_received; + metrics->num_bytes_transmitted = num_bytes_transmitted; + metrics->num_dropped_packets = num_dropped_packets; + metrics->num_l7_bytes_received = num_l7_bytes_received; + metrics->num_l7_bytes_transmitted = num_l7_bytes_transmitted; + metrics->num_lost_packets = num_lost_packets; + metrics->num_out_of_order_packets = num_out_of_order_packets; + metrics->num_packet_errors = num_packet_errors; + metrics->num_packets_received_excl_retrans = + num_packets_received_excl_retrans; + metrics->num_packets_received_incl_retrans = + num_packets_received_incl_retrans; + metrics->num_packets_transmitted_incl_retrans = + num_packets_transmitted_incl_retrans; + metrics->num_retries = num_retries; + metrics->num_timeouts = num_timeouts; + metrics->num_tunneled_l7_bytes_received = num_tunneled_l7_bytes_received; + metrics->round_trip_time = round_trip_time; + metrics->time_to_first_byte = time_to_first_byte; + for (ii = 0; ii < EVEL_TOS_SUPPORTED; ii++) + { + evel_init_option_int(&metrics->ip_tos_counts[ii]); + } + for (ii = 0; ii < EVEL_MAX_TCP_FLAGS; ii++) + { + evel_init_option_int(&metrics->tcp_flag_counts[ii]); + } + for (ii = 0; ii < EVEL_MAX_QCI_COS_TYPES; ii++) + { + evel_init_option_int(&metrics->qci_cos_counts[ii]); + } + evel_init_option_int(&metrics->dur_connection_failed_status); + evel_init_option_int(&metrics->dur_tunnel_failed_status); + evel_init_option_string(&metrics->flow_activated_by); + evel_init_option_time(&metrics->flow_activation_time); + evel_init_option_string(&metrics->flow_deactivated_by); + evel_init_option_string(&metrics->gtp_connection_status); + evel_init_option_string(&metrics->gtp_tunnel_status); + evel_init_option_int(&metrics->large_packet_rtt); + evel_init_option_double(&metrics->large_packet_threshold); + evel_init_option_int(&metrics->max_receive_bit_rate); + evel_init_option_int(&metrics->max_transmit_bit_rate); + evel_init_option_int(&metrics->num_gtp_echo_failures); + evel_init_option_int(&metrics->num_gtp_tunnel_errors); + evel_init_option_int(&metrics->num_http_errors); + +exit_label: + EVEL_EXIT(); + return metrics; +} + +/**************************************************************************//** + * Set the Duration of Connection Failed Status property of the Mobile GTP Per + * Flow Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param duration The Duration of Connection Failed Status to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_dur_con_fail_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int duration) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(duration >= 0); + + evel_set_option_int(&metrics->dur_connection_failed_status, + duration, + "Duration of Connection Failed Status"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Duration of Tunnel Failed Status property of the Mobile GTP Per Flow + * Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param duration The Duration of Tunnel Failed Status to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_dur_tun_fail_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int duration) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(duration >= 0); + + evel_set_option_int(&metrics->dur_tunnel_failed_status, + duration, + "Duration of Tunnel Failed Status"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Activated By property of the Mobile GTP Per Flow metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param act_by The Activated By to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_mobile_gtp_metrics_act_by_set(MOBILE_GTP_PER_FLOW_METRICS * metrics, + const char * const act_by) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(act_by != NULL); + + evel_set_option_string(&metrics->flow_activated_by, + act_by, + "Activated By"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Activation Time property of the Mobile GTP Per Flow metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param act_time The Activation Time to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_mobile_gtp_metrics_act_time_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + time_t act_time) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(act_time > 0); + + evel_set_option_time(&metrics->flow_activation_time, + act_time, + "Activation Time"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Deactivated By property of the Mobile GTP Per Flow metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param deact_by The Deactivated By to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_mobile_gtp_metrics_deact_by_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + const char * const deact_by) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(deact_by != NULL); + + evel_set_option_string(&metrics->flow_deactivated_by, + deact_by, + "Deactivated By"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the GTP Connection Status property of the Mobile GTP Per Flow metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param status The GTP Connection Status to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_gtp_metrics_con_status_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + const char * const status) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(status != NULL); + + evel_set_option_string(&metrics->gtp_connection_status, + status, + "GTP Connection Status"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the GTP Tunnel Status property of the Mobile GTP Per Flow metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param status The GTP Tunnel Status to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_mobile_gtp_metrics_tun_status_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + const char * const status) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(status != NULL); + + evel_set_option_string(&metrics->gtp_tunnel_status, + status, + "GTP Tunnel Status"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set an IP Type-of-Service count property of the Mobile GTP Per Flow metrics. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param index The index of the IP Type-of-Service. + * @param count The count. + *****************************************************************************/ +void evel_mobile_gtp_metrics_iptos_set(MOBILE_GTP_PER_FLOW_METRICS * metrics, + int index, + int count) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(index >= 0); + assert(index < EVEL_TOS_SUPPORTED); + assert(count >= 0); + assert(count <= 255); + + EVEL_DEBUG("IP Type-of-Service %d", index); + evel_set_option_int(&metrics->ip_tos_counts[index], + count, + "IP Type-of-Service"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Large Packet Round-Trip Time property of the Mobile GTP Per Flow + * Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param rtt The Large Packet Round-Trip Time to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_large_pkt_rtt_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int rtt) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(rtt >= 0); + + evel_set_option_int(&metrics->large_packet_rtt, + rtt, + "Large Packet Round-Trip Time"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Large Packet Threshold property of the Mobile GTP Per Flow Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param threshold The Large Packet Threshold to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_large_pkt_thresh_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + double threshold) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(threshold >= 0.0); + + evel_set_option_double(&metrics->large_packet_threshold, + threshold, + "Large Packet Threshold"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Max Receive Bit Rate property of the Mobile GTP Per Flow Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param rate The Max Receive Bit Rate to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_max_rcv_bit_rate_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int rate) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(rate >= 0); + + evel_set_option_int(&metrics->max_receive_bit_rate, + rate, + "Max Receive Bit Rate"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Max Transmit Bit Rate property of the Mobile GTP Per Flow Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param rate The Max Transmit Bit Rate to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_max_trx_bit_rate_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int rate) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(rate >= 0); + + evel_set_option_int(&metrics->max_transmit_bit_rate, + rate, + "Max Transmit Bit Rate"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Number of GTP Echo Failures property of the Mobile GTP Per Flow + * Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param num The Number of GTP Echo Failures to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_num_echo_fail_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int num) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(num >= 0); + + evel_set_option_int(&metrics->num_gtp_echo_failures, + num, + "Number of GTP Echo Failures"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Number of GTP Tunnel Errors property of the Mobile GTP Per Flow + * Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param num The Number of GTP Tunnel Errors to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_num_tun_fail_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int num) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(num >= 0); + + evel_set_option_int(&metrics->num_gtp_tunnel_errors, + num, + "Number of GTP Tunnel Errors"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Number of HTTP Errors property of the Mobile GTP Per Flow Metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param num The Number of HTTP Errors to be set. + *****************************************************************************/ +void evel_mobile_gtp_metrics_num_http_errors_set( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + int num) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(num >= 0); + + evel_set_option_int(&metrics->num_http_errors, + num, + "Number of HTTP Errors"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add a TCP flag count to the metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param tcp_flag The TCP flag to be updated. + * @param count The associated flag count, which must be nonzero. + *****************************************************************************/ +void evel_mobile_gtp_metrics_tcp_flag_count_add( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + const EVEL_TCP_FLAGS tcp_flag, + const int count) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(tcp_flag >= 0); + assert(tcp_flag < EVEL_MAX_TCP_FLAGS); + assert(count >= 0); + + EVEL_DEBUG("TCP Flag: %d", tcp_flag); + evel_set_option_int(&metrics->tcp_flag_counts[tcp_flag], + count, + "TCP flag"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add a QCI COS count to the metrics. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param metrics Pointer to the Mobile GTP Per Flow Metrics. + * @param qci_cos The QCI COS count to be updated. + * @param count The associated QCI COS count. + *****************************************************************************/ +void evel_mobile_gtp_metrics_qci_cos_count_add( + MOBILE_GTP_PER_FLOW_METRICS * metrics, + const EVEL_QCI_COS_TYPES qci_cos, + const int count) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + assert(qci_cos >= 0); + assert(qci_cos < EVEL_MAX_QCI_COS_TYPES); + assert(count >= 0); + + EVEL_DEBUG("QCI COS: %d", qci_cos); + evel_set_option_int(&metrics->qci_cos_counts[qci_cos], + count, + "QCI COS"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the Mobile Flow GTP Per Flow Metrics as a JSON object. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param metrics Pointer to the ::EVENT_MOBILE_FLOW to encode. + * @returns Number of bytes actually written. + *****************************************************************************/ +void evel_json_encode_mobile_flow_gtp_flow_metrics( + EVEL_JSON_BUFFER * jbuf, + MOBILE_GTP_PER_FLOW_METRICS * metrics) +{ + int index; + bool found_ip_tos; + bool found_tcp_flag; + bool found_qci_cos; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(metrics != NULL); + + evel_json_open_named_object(jbuf, "gtpPerFlowMetrics"); + + /***************************************************************************/ + /* Mandatory parameters. */ + /***************************************************************************/ + evel_enc_kv_double(jbuf, "avgBitErrorRate", metrics->avg_bit_error_rate); + evel_enc_kv_double( + jbuf, "avgPacketDelayVariation", metrics->avg_packet_delay_variation); + evel_enc_kv_int(jbuf, "avgPacketLatency", metrics->avg_packet_latency); + evel_enc_kv_int( + jbuf, "avgReceiveThroughput", metrics->avg_receive_throughput); + evel_enc_kv_int( + jbuf, "avgTransmitThroughput", metrics->avg_transmit_throughput); + evel_enc_kv_int(jbuf, "flowActivationEpoch", metrics->flow_activation_epoch); + evel_enc_kv_int( + jbuf, "flowActivationMicrosec", metrics->flow_activation_microsec); + evel_enc_kv_int( + jbuf, "flowDeactivationEpoch", metrics->flow_deactivation_epoch); + evel_enc_kv_int( + jbuf, "flowDeactivationMicrosec", metrics->flow_deactivation_microsec); + evel_enc_kv_time( + jbuf, "flowDeactivationTime", &metrics->flow_deactivation_time); + evel_enc_kv_string(jbuf, "flowStatus", metrics->flow_status); + evel_enc_kv_int( + jbuf, "maxPacketDelayVariation", metrics->max_packet_delay_variation); + evel_enc_kv_int( + jbuf, "numActivationFailures", metrics->num_activation_failures); + evel_enc_kv_int(jbuf, "numBitErrors", metrics->num_bit_errors); + evel_enc_kv_int(jbuf, "numBytesReceived", metrics->num_bytes_received); + evel_enc_kv_int(jbuf, "numBytesTransmitted", metrics->num_bytes_transmitted); + evel_enc_kv_int(jbuf, "numDroppedPackets", metrics->num_dropped_packets); + evel_enc_kv_int(jbuf, "numL7BytesReceived", metrics->num_l7_bytes_received); + evel_enc_kv_int( + jbuf, "numL7BytesTransmitted", metrics->num_l7_bytes_transmitted); + evel_enc_kv_int(jbuf, "numLostPackets", metrics->num_lost_packets); + evel_enc_kv_int( + jbuf, "numOutOfOrderPackets", metrics->num_out_of_order_packets); + evel_enc_kv_int(jbuf, "numPacketErrors", metrics->num_packet_errors); + evel_enc_kv_int(jbuf, + "numPacketsReceivedExclRetrans", + metrics->num_packets_received_excl_retrans); + evel_enc_kv_int(jbuf, + "numPacketsReceivedInclRetrans", + metrics->num_packets_received_incl_retrans); + evel_enc_kv_int(jbuf, + "numPacketsTransmittedInclRetrans", + metrics->num_packets_transmitted_incl_retrans); + evel_enc_kv_int(jbuf, "numRetries", metrics->num_retries); + evel_enc_kv_int(jbuf, "numTimeouts", metrics->num_timeouts); + evel_enc_kv_int(jbuf, + "numTunneledL7BytesReceived", + metrics->num_tunneled_l7_bytes_received); + evel_enc_kv_int(jbuf, "roundTripTime", metrics->round_trip_time); + evel_enc_kv_int(jbuf, "timeToFirstByte", metrics->time_to_first_byte); + + /***************************************************************************/ + /* Optional parameters. */ + /***************************************************************************/ + found_ip_tos = false; + for (index = 0; index < EVEL_TOS_SUPPORTED; index++) + { + if (metrics->ip_tos_counts[index].is_set) + { + found_ip_tos = true; + break; + } + } + + if (found_ip_tos) + { + evel_json_open_named_list(jbuf, "ipTosCountList"); + for (index = 0; index < EVEL_TOS_SUPPORTED; index++) + { + if (metrics->ip_tos_counts[index].is_set) + { + evel_enc_list_item(jbuf, + "[\"%d\", %d]", + index, + metrics->ip_tos_counts[index].value); + } + } + evel_json_close_list(jbuf); + } + + if (found_ip_tos) + { + evel_json_open_named_list(jbuf, "ipTosList"); + for (index = 0; index < EVEL_TOS_SUPPORTED; index++) + { + if (metrics->ip_tos_counts[index].is_set) + { + evel_enc_list_item(jbuf, "\"%d\"", index); + } + } + evel_json_close_list(jbuf); + } + + /***************************************************************************/ + /* Make some compile-time assertions about EVEL_TCP_FLAGS. If you update */ + /* these, make sure you update evel_tcp_flag_strings to match the enum. */ + /***************************************************************************/ + EVEL_CT_ASSERT(EVEL_TCP_NS == 0); + EVEL_CT_ASSERT(EVEL_TCP_CWR == 1); + EVEL_CT_ASSERT(EVEL_TCP_ECE == 2); + EVEL_CT_ASSERT(EVEL_TCP_URG == 3); + EVEL_CT_ASSERT(EVEL_TCP_ACK == 4); + EVEL_CT_ASSERT(EVEL_TCP_PSH == 5); + EVEL_CT_ASSERT(EVEL_TCP_RST == 6); + EVEL_CT_ASSERT(EVEL_TCP_SYN == 7); + EVEL_CT_ASSERT(EVEL_TCP_FIN == 8); + EVEL_CT_ASSERT(EVEL_MAX_TCP_FLAGS == 9); + + found_tcp_flag = false; + for (index = 0; index < EVEL_MAX_TCP_FLAGS; index++) + { + if (metrics->tcp_flag_counts[index].is_set) + { + found_tcp_flag = true; + break; + } + } + + if (found_tcp_flag) + { + evel_json_open_named_list(jbuf, "tcpFlagList"); + for (index = 0; index < EVEL_MAX_TCP_FLAGS; index++) + { + if (metrics->tcp_flag_counts[index].is_set) + { + evel_enc_list_item(jbuf, + "\"%s\"", + evel_tcp_flag_strings[index]); + } + } + evel_json_close_list(jbuf); + } + + if (found_tcp_flag) + { + evel_json_open_named_list(jbuf, "tcpFlagCountList"); + for (index = 0; index < EVEL_MAX_TCP_FLAGS; index++) + { + if (metrics->tcp_flag_counts[index].is_set) + { + evel_enc_list_item(jbuf, + "[\"%s\", %d]", + evel_tcp_flag_strings[index], + metrics->tcp_flag_counts[index].value); + } + } + evel_json_close_list(jbuf); + } + + /***************************************************************************/ + /* Make some compile-time assertions about EVEL_QCI_COS_TYPES. If you */ + /* update these, make sure you update evel_qci_cos_strings to match the */ + /* enum. */ + /***************************************************************************/ + EVEL_CT_ASSERT(EVEL_QCI_COS_UMTS_CONVERSATIONAL ==0); + EVEL_CT_ASSERT(EVEL_QCI_COS_UMTS_STREAMING == 1); + EVEL_CT_ASSERT(EVEL_QCI_COS_UMTS_INTERACTIVE == 2); + EVEL_CT_ASSERT(EVEL_QCI_COS_UMTS_BACKGROUND == 3); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_1 == 4); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_2 == 5); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_3 == 6); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_4 == 7); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_65 == 8); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_66 == 9); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_5 == 10); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_6 == 11); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_7 == 12); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_8 == 13); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_9 == 14); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_69 == 15); + EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_70 == 16); + EVEL_CT_ASSERT(EVEL_MAX_QCI_COS_TYPES == 17); + + found_qci_cos = false; + for (index = 0; index < EVEL_MAX_QCI_COS_TYPES; index++) + { + if (metrics->qci_cos_counts[index].is_set) + { + found_qci_cos = true; + break; + } + } + + if (found_qci_cos) + { + evel_json_open_named_list(jbuf, "mobileQciCosList"); + for (index = 0; index < EVEL_MAX_QCI_COS_TYPES; index++) + { + if (metrics->qci_cos_counts[index].is_set) + { + evel_enc_list_item(jbuf, + "\"%s\"", + evel_qci_cos_strings[index]); + } + } + evel_json_close_list(jbuf); + } + + if (found_qci_cos) + { + evel_json_open_named_list(jbuf, "mobileQciCosCountList"); + for (index = 0; index < EVEL_MAX_QCI_COS_TYPES; index++) + { + if (metrics->qci_cos_counts[index].is_set) + { + evel_enc_list_item(jbuf, + "[\"%s\", %d]", + evel_qci_cos_strings[index], + metrics->qci_cos_counts[index].value); + } + } + evel_json_close_list(jbuf); + } + + evel_enc_kv_opt_int( + jbuf, "durConnectionFailedStatus", &metrics->dur_connection_failed_status); + evel_enc_kv_opt_int( + jbuf, "durTunnelFailedStatus", &metrics->dur_tunnel_failed_status); + evel_enc_kv_opt_string(jbuf, "flowActivatedBy", &metrics->flow_activated_by); + evel_enc_kv_opt_time( + jbuf, "flowActivationTime", &metrics->flow_activation_time); + evel_enc_kv_opt_string( + jbuf, "flowDeactivatedBy", &metrics->flow_deactivated_by); + evel_enc_kv_opt_string( + jbuf, "gtpConnectionStatus", &metrics->gtp_connection_status); + evel_enc_kv_opt_string(jbuf, "gtpTunnelStatus", &metrics->gtp_tunnel_status); + evel_enc_kv_opt_int(jbuf, "largePacketRtt", &metrics->large_packet_rtt); + evel_enc_kv_opt_double( + jbuf, "largePacketThreshold", &metrics->large_packet_threshold); + evel_enc_kv_opt_int( + jbuf, "maxReceiveBitRate", &metrics->max_receive_bit_rate); + evel_enc_kv_opt_int( + jbuf, "maxTransmitBitRate", &metrics->max_transmit_bit_rate); + evel_enc_kv_opt_int( + jbuf, "numGtpEchoFailures", &metrics->num_gtp_echo_failures); + evel_enc_kv_opt_int( + jbuf, "numGtpTunnelErrors", &metrics->num_gtp_tunnel_errors); + evel_enc_kv_opt_int(jbuf, "numHttpErrors", &metrics->num_http_errors); + + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free a Mobile GTP Per Flow Metrics. + * + * Free off the Mobile GTP Per Flow Metrics supplied. Will free all the + * contained allocated memory. + * + * @note It does not free the Mobile GTP Per Flow Metrics itself, since that + * may be part of a larger structure. + *****************************************************************************/ +void evel_free_mobile_gtp_flow_metrics(MOBILE_GTP_PER_FLOW_METRICS * metrics) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(metrics != NULL); + + /***************************************************************************/ + /* Free all internal strings. */ + /***************************************************************************/ + free(metrics->flow_status); + + evel_free_option_string(&metrics->flow_activated_by); + evel_free_option_string(&metrics->flow_deactivated_by); + evel_free_option_string(&metrics->gtp_connection_status); + evel_free_option_string(&metrics->gtp_tunnel_status); + + EVEL_EXIT(); +} \ No newline at end of file diff --git a/vnfs/VES/code/evel_library/evel_option.c b/vnfs/VES/code/evel_library/evel_option.c new file mode 100644 index 00000000..fe714b53 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_option.c @@ -0,0 +1,442 @@ +/**************************************************************************//** + * @file + * Source module relating to EVEL_OPTION_ types. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include + +#include "evel_internal.h" + +/**************************************************************************//** + * Free the underlying resources of an ::EVEL_OPTION_STRING. + * + * @param option Pointer to the ::EVEL_OPTION_STRING. + *****************************************************************************/ +void evel_free_option_string(EVEL_OPTION_STRING * const option) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + if (option->is_set) + { + free(option->value); + option->value = NULL; + option->is_set = EVEL_FALSE; + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Initialize an ::EVEL_OPTION_STRING to a not-set state. + * + * @param option Pointer to the ::EVEL_OPTION_STRING. + *****************************************************************************/ +void evel_init_option_string(EVEL_OPTION_STRING * const option) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + option->value = NULL; + option->is_set = EVEL_FALSE; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the value of an ::EVEL_OPTION_STRING. + * + * @param option Pointer to the ::EVEL_OPTION_STRING. + * @param value The value to set. + * @param description Description to be used in logging. + *****************************************************************************/ +void evel_set_option_string(EVEL_OPTION_STRING * const option, + const char * const value, + const char * const description) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + assert(value != NULL); + assert(description != NULL); + + if (option->is_set) + { + EVEL_ERROR("Ignoring attempt to update %s to %s. %s already set to %s", + description, value, description, option->value); + } + else + { + EVEL_DEBUG("Setting %s to %s", description, value); + option->value = strdup(value); + option->is_set = EVEL_TRUE; + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Force the value of an ::EVEL_OPTION_STRING. + * + * @param option Pointer to the ::EVEL_OPTION_STRING. + * @param value The value to set. + *****************************************************************************/ +void evel_force_option_string(EVEL_OPTION_STRING * const option, + const char * const value) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + assert(option->is_set == EVEL_FALSE); + assert(option->value == NULL); + + option->value = strdup(value); + option->is_set = EVEL_TRUE; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Initialize an ::EVEL_OPTION_INT to a not-set state. + * + * @param option Pointer to the ::EVEL_OPTION_INT. + *****************************************************************************/ +void evel_init_option_int(EVEL_OPTION_INT * const option) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + option->value = 0; + option->is_set = EVEL_FALSE; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Force the value of an ::EVEL_OPTION_INT. + * + * @param option Pointer to the ::EVEL_OPTION_INT. + * @param value The value to set. + *****************************************************************************/ +void evel_force_option_int(EVEL_OPTION_INT * const option, + const int value) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + option->value = value; + option->is_set = EVEL_TRUE; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the value of an ::EVEL_OPTION_INT. + * + * @param option Pointer to the ::EVEL_OPTION_INT. + * @param value The value to set. + * @param description Description to be used in logging. + *****************************************************************************/ +void evel_set_option_int(EVEL_OPTION_INT * const option, + const int value, + const char * const description) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + assert(description != NULL); + + if (option->is_set) + { + EVEL_ERROR("Ignoring attempt to update %s to %d. %s already set to %d", + description, value, description, option->value); + } + else + { + EVEL_DEBUG("Setting %s to %d", description, value); + option->value = value; + option->is_set = EVEL_TRUE; + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Initialize an ::EVEL_OPTION_DOUBLE to a not-set state. + * + * @param option Pointer to the ::EVEL_OPTION_DOUBLE. + *****************************************************************************/ +void evel_init_option_double(EVEL_OPTION_DOUBLE * const option) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + option->value = 0.0; + option->is_set = EVEL_FALSE; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Force the value of an ::EVEL_OPTION_DOUBLE. + * + * @param option Pointer to the ::EVEL_OPTION_DOUBLE. + * @param value The value to set. + *****************************************************************************/ +void evel_force_option_double(EVEL_OPTION_DOUBLE * const option, + const double value) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + option->value = value; + option->is_set = EVEL_TRUE; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the value of an ::EVEL_OPTION_DOUBLE. + * + * @param option Pointer to the ::EVEL_OPTION_DOUBLE. + * @param value The value to set. + * @param description Description to be used in logging. + *****************************************************************************/ +void evel_set_option_double(EVEL_OPTION_DOUBLE * const option, + const double value, + const char * const description) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + assert(description != NULL); + + if (option->is_set) + { + EVEL_ERROR("Ignoring attempt to update %s to %lf. %s already set to %lf", + description, value, description, option->value); + } + else + { + EVEL_DEBUG("Setting %s to %lf", description, value); + option->value = value; + option->is_set = EVEL_TRUE; + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Initialize an ::EVEL_OPTION_ULL to a not-set state. + * + * @param option Pointer to the ::EVEL_OPTION_ULL. + *****************************************************************************/ +void evel_init_option_ull(EVEL_OPTION_ULL * const option) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + option->value = 0; + option->is_set = EVEL_FALSE; + EVEL_EXIT(); +} + +/**************************************************************************//** + * Force the value of an ::EVEL_OPTION_ULL. + * + * @param option Pointer to the ::EVEL_OPTION_ULL. + * @param value The value to set. + *****************************************************************************/ +void evel_force_option_ull(EVEL_OPTION_ULL * const option, + const unsigned long long value) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + option->value = value; + option->is_set = EVEL_TRUE; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the value of an ::EVEL_OPTION_ULL. + * + * @param option Pointer to the ::EVEL_OPTION_ULL. + * @param value The value to set. + * @param description Description to be used in logging. + *****************************************************************************/ +void evel_set_option_ull(EVEL_OPTION_ULL * const option, + const unsigned long long value, + const char * const description) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + assert(description != NULL); + + if (option->is_set) + { + EVEL_ERROR("Ignoring attempt to update %s to %llu. %s already set to %llu", + description, value, description, option->value); + } + else + { + EVEL_DEBUG("Setting %s to %llu", description, value); + option->value = value; + option->is_set = EVEL_TRUE; + } + EVEL_EXIT(); +} + +/**************************************************************************//** + * Initialize an ::EVEL_OPTION_TIME to a not-set state. + * + * @param option Pointer to the ::EVEL_OPTION_TIME. + *****************************************************************************/ +void evel_init_option_time(EVEL_OPTION_TIME * const option) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + option->value = 0; + option->is_set = EVEL_FALSE; + EVEL_EXIT(); +} + +/**************************************************************************//** + * Force the value of an ::EVEL_OPTION_TIME. + * + * @param option Pointer to the ::EVEL_OPTION_TIME. + * @param value The value to set. + *****************************************************************************/ +void evel_force_option_time(EVEL_OPTION_TIME * const option, + const time_t value) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + option->value = value; + option->is_set = EVEL_TRUE; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the value of an ::EVEL_OPTION_TIME. + * + * @param option Pointer to the ::EVEL_OPTION_TIME. + * @param value The value to set. + * @param description Description to be used in logging. + *****************************************************************************/ +void evel_set_option_time(EVEL_OPTION_TIME * const option, + const time_t value, + const char * const description) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + assert(description != NULL); + + if (option->is_set) + { + EVEL_ERROR("Ignoring attempt to update %s to %d. %s already set to %d", + description, value, description, option->value); + } + else + { + EVEL_DEBUG("Setting %s to %d", description, value); + option->value = value; + option->is_set = EVEL_TRUE; + } + EVEL_EXIT(); +} diff --git a/vnfs/VES/code/evel_library/evel_other.c b/vnfs/VES/code/evel_library/evel_other.c new file mode 100644 index 00000000..f63a091a --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_other.c @@ -0,0 +1,231 @@ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to Other. + * + * License + * ------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include + +#include "evel.h" +#include "evel_internal.h" + +/**************************************************************************//** + * Create a new Other event. + * + * @note The mandatory fields on the Other must be supplied to this factory + * function and are immutable once set. Optional fields have explicit + * setter functions, but again values may only be set once so that the + * Other has immutable properties. + * @returns pointer to the newly manufactured ::EVENT_OTHER. If the event is + * not used (i.e. posted) it must be released using ::evel_free_other. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_OTHER * evel_new_other() +{ + EVENT_OTHER * other = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + + /***************************************************************************/ + /* Allocate the Other. */ + /***************************************************************************/ + other = malloc(sizeof(EVENT_OTHER)); + if (other == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(other, 0, sizeof(EVENT_OTHER)); + EVEL_DEBUG("New Other is at %lp", other); + + /***************************************************************************/ + /* Initialize the header & the Other fields. Optional string values are */ + /* uninitialized (NULL). */ + /***************************************************************************/ + evel_init_header(&other->header); + other->header.event_domain = EVEL_DOMAIN_OTHER; + dlist_initialize(&other->other_fields); + +exit_label: + EVEL_EXIT(); + return other; +} + +/**************************************************************************//** + * Set the Event Type property of the Other. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param other Pointer to the Other. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_other_type_set(EVENT_OTHER * other, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(other != NULL); + assert(other->header.event_domain == EVEL_DOMAIN_OTHER); + evel_header_type_set(&other->header, type); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add a field name/value pair to the Other. + * + * The name and value are null delimited ASCII strings. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param other Pointer to the Other. + * @param name ASCIIZ string with the field's name. The caller does not + * need to preserve the value once the function returns. + * @param value ASCIIZ string with the field's value. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_other_field_add(EVENT_OTHER * other, char * name, char * value) +{ + OTHER_FIELD * other_field = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(other != NULL); + assert(other->header.event_domain == EVEL_DOMAIN_OTHER); + assert(name != NULL); + assert(value != NULL); + + EVEL_DEBUG("Adding name=%s value=%s", name, value); + other_field = malloc(sizeof(OTHER_FIELD)); + assert(other_field != NULL); + memset(other_field, 0, sizeof(OTHER_FIELD)); + other_field->name = strdup(name); + other_field->value = strdup(value); + assert(other_field->name != NULL); + assert(other_field->value != NULL); + + dlist_push_last(&other->other_fields, other_field); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the Other in JSON according to AT&T's schema for the event type. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_other(EVEL_JSON_BUFFER * jbuf, + EVENT_OTHER * event) +{ + OTHER_FIELD * other_field = NULL; + DLIST_ITEM * other_field_item = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_OTHER); + + evel_json_encode_header(jbuf, &event->header); + evel_json_open_named_list(jbuf, "otherFields"); + other_field_item = dlist_get_first(&event->other_fields); + while (other_field_item != NULL) + { + other_field = (OTHER_FIELD *) other_field_item->item; + assert(other_field != NULL); + + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "name", other_field->name); + evel_enc_kv_string(jbuf, "value", other_field->value); + evel_json_close_object(jbuf); + other_field_item = dlist_get_next(other_field_item); + } + evel_json_close_list(jbuf); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free an Other. + * + * Free off the Other supplied. Will free all the contained allocated memory. + * + * @note It does not free the Other itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_other(EVENT_OTHER * event) +{ + OTHER_FIELD * other_field = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the public API. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_OTHER); + + /***************************************************************************/ + /* Free all internal strings then the header itself. */ + /***************************************************************************/ + other_field = dlist_pop_last(&event->other_fields); + while (other_field != NULL) + { + EVEL_DEBUG("Freeing Other Field (%s, %s)", + other_field->name, + other_field->value); + free(other_field->name); + free(other_field->value); + free(other_field); + other_field = dlist_pop_last(&event->other_fields); + } + evel_free_header(&event->header); + + EVEL_EXIT(); +} \ No newline at end of file diff --git a/vnfs/VES/code/evel_library/evel_reporting_measurement.c b/vnfs/VES/code/evel_library/evel_reporting_measurement.c new file mode 100644 index 00000000..84552934 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_reporting_measurement.c @@ -0,0 +1,450 @@ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the Measurement for VF + * Reporting event. + * + * @note This is an experimental event tytpe and does not form part of the + * currently approved AT&T event schema. It is intended to allow a + * less-onerous event reporting mechanism because it avoids having to + * return all the platform statistics which are mandatory in the + * **measurementsForVfScaling** event. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include + +#include "evel.h" +#include "evel_internal.h" +#include "evel_throttle.h" + +/**************************************************************************//** + * Create a new Report event. + * + * @note The mandatory fields on the Report must be supplied to this + * factory function and are immutable once set. Optional fields have + * explicit setter functions, but again values may only be set once so + * that the Report has immutable properties. + * + * @param measurement_interval + + * @returns pointer to the newly manufactured ::EVENT_REPORT. If the event is + * not used (i.e. posted) it must be released using ::evel_free_event. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_REPORT * evel_new_report(double measurement_interval) +{ + EVENT_REPORT * report = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement_interval >= 0.0); + + /***************************************************************************/ + /* Allocate the report. */ + /***************************************************************************/ + report = malloc(sizeof(EVENT_REPORT)); + if (report == NULL) + { + log_error_state("Out of memory for Report"); + goto exit_label; + } + memset(report, 0, sizeof(EVENT_REPORT)); + EVEL_DEBUG("New report is at %lp", report); + + /***************************************************************************/ + /* Initialize the header & the report fields. */ + /***************************************************************************/ + evel_init_header(&report->header); + report->header.event_domain = EVEL_DOMAIN_REPORT; + report->measurement_interval = measurement_interval; + + dlist_initialize(&report->feature_usage); + dlist_initialize(&report->measurement_groups); + report->major_version = EVEL_REPORT_MAJOR_VERSION; + report->minor_version = EVEL_REPORT_MINOR_VERSION; + +exit_label: + EVEL_EXIT(); + return report; +} + +/**************************************************************************//** + * Set the Event Type property of the Report. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param report Pointer to the Report. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_report_type_set(EVENT_REPORT * report, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(report != NULL); + assert(report->header.event_domain == EVEL_DOMAIN_REPORT); + evel_header_type_set(&report->header, type); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add a Feature usage value name/value pair to the Report. + * + * The name is null delimited ASCII string. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param report Pointer to the report. + * @param feature ASCIIZ string with the feature's name. + * @param utilization Utilization of the feature. + *****************************************************************************/ +void evel_report_feature_use_add(EVENT_REPORT * report, + char * feature, + int utilization) +{ + MEASUREMENT_FEATURE_USE * feature_use = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(report != NULL); + assert(report->header.event_domain == EVEL_DOMAIN_REPORT); + assert(feature != NULL); + assert(utilization >= 0); + + /***************************************************************************/ + /* Allocate a container for the value and push onto the list. */ + /***************************************************************************/ + EVEL_DEBUG("Adding Feature=%s Use=%d", feature, utilization); + feature_use = malloc(sizeof(MEASUREMENT_FEATURE_USE)); + assert(feature_use != NULL); + memset(feature_use, 0, sizeof(MEASUREMENT_FEATURE_USE)); + feature_use->feature_id = strdup(feature); + assert(feature_use->feature_id != NULL); + feature_use->feature_utilization = utilization; + + dlist_push_last(&report->feature_usage, feature_use); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add a Additional Measurement value name/value pair to the Report. + * + * The name is null delimited ASCII string. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param report Pointer to the report. + * @param group ASCIIZ string with the measurement group's name. + * @param name ASCIIZ string containing the measurement's name. + * @param value ASCIIZ string containing the measurement's value. + *****************************************************************************/ +void evel_report_custom_measurement_add(EVENT_REPORT * report, + const char * const group, + const char * const name, + const char * const value) +{ + MEASUREMENT_GROUP * measurement_group = NULL; + CUSTOM_MEASUREMENT * measurement = NULL; + DLIST_ITEM * item = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(report != NULL); + assert(report->header.event_domain == EVEL_DOMAIN_REPORT); + assert(group != NULL); + assert(name != NULL); + assert(value != NULL); + + /***************************************************************************/ + /* Allocate a container for the name/value pair. */ + /***************************************************************************/ + EVEL_DEBUG("Adding Measurement Group=%s Name=%s Value=%s", + group, name, value); + measurement = malloc(sizeof(CUSTOM_MEASUREMENT)); + assert(measurement != NULL); + memset(measurement, 0, sizeof(CUSTOM_MEASUREMENT)); + measurement->name = strdup(name); + assert(measurement->name != NULL); + measurement->value = strdup(value); + assert(measurement->value != NULL); + + /***************************************************************************/ + /* See if we have that group already. */ + /***************************************************************************/ + item = dlist_get_first(&report->measurement_groups); + while (item != NULL) + { + measurement_group = (MEASUREMENT_GROUP *) item->item; + assert(measurement_group != NULL); + + EVEL_DEBUG("Got measurement group %s", measurement_group->name); + if (strcmp(group, measurement_group->name) == 0) + { + EVEL_DEBUG("Found existing Measurement Group"); + break; + } + item = dlist_get_next(item); + } + + /***************************************************************************/ + /* If we didn't have the group already, create it. */ + /***************************************************************************/ + if (item == NULL) + { + EVEL_DEBUG("Creating new Measurement Group"); + measurement_group = malloc(sizeof(MEASUREMENT_GROUP)); + assert(measurement_group != NULL); + memset(measurement_group, 0, sizeof(MEASUREMENT_GROUP)); + measurement_group->name = strdup(group); + assert(measurement_group->name != NULL); + dlist_initialize(&measurement_group->measurements); + dlist_push_last(&report->measurement_groups, measurement_group); + } + + /***************************************************************************/ + /* If we didn't have the group already, create it. */ + /***************************************************************************/ + dlist_push_last(&measurement_group->measurements, measurement); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the report as a JSON report. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_report(EVEL_JSON_BUFFER * jbuf, + EVENT_REPORT * event) +{ + MEASUREMENT_FEATURE_USE * feature_use = NULL; + MEASUREMENT_GROUP * measurement_group = NULL; + CUSTOM_MEASUREMENT * custom_measurement = NULL; + DLIST_ITEM * item = NULL; + DLIST_ITEM * nested_item = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_REPORT); + + evel_json_encode_header(jbuf, &event->header); + evel_json_open_named_object(jbuf, "measurementsForVfReportingFields"); + evel_enc_kv_double(jbuf, "measurementInterval", event->measurement_interval); + + /***************************************************************************/ + /* Feature Utilization list. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "featureUsageArray")) + { + bool item_added = false; + + item = dlist_get_first(&event->feature_usage); + while (item != NULL) + { + feature_use = (MEASUREMENT_FEATURE_USE*) item->item; + assert(feature_use != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "featureUsageArray", + feature_use->feature_id)) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "featureIdentifier", feature_use->feature_id); + evel_enc_kv_int( + jbuf, "featureUtilization", feature_use->feature_utilization); + evel_json_close_object(jbuf); + item_added = true; + } + item = dlist_get_next(item); + } + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + if (!item_added) + { + evel_json_rewind(jbuf); + } + } + + /***************************************************************************/ + /* Additional Measurement Groups list. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "additionalMeasurements")) + { + bool item_added = false; + + item = dlist_get_first(&event->measurement_groups); + while (item != NULL) + { + measurement_group = (MEASUREMENT_GROUP *) item->item; + assert(measurement_group != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "additionalMeasurements", + measurement_group->name)) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "name", measurement_group->name); + evel_json_open_named_list(jbuf, "measurements"); + + /*********************************************************************/ + /* Measurements list. */ + /*********************************************************************/ + nested_item = dlist_get_first(&measurement_group->measurements); + while (nested_item != NULL) + { + custom_measurement = (CUSTOM_MEASUREMENT *) nested_item->item; + assert(custom_measurement != NULL); + + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "name", custom_measurement->name); + evel_enc_kv_string(jbuf, "value", custom_measurement->value); + evel_json_close_object(jbuf); + nested_item = dlist_get_next(nested_item); + } + evel_json_close_list(jbuf); + evel_json_close_object(jbuf); + item_added = true; + } + item = dlist_get_next(item); + } + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + if (!item_added) + { + evel_json_rewind(jbuf); + } + } + + /***************************************************************************/ + /* Although optional, we always generate the version. Note that this */ + /* closes the object, too. */ + /***************************************************************************/ + evel_enc_version(jbuf, + "measurementFieldsVersion", + event->major_version, + event->major_version); + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free a Report. + * + * Free off the Report supplied. Will free all the contained allocated memory. + * + * @note It does not free the Report itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_report(EVENT_REPORT * event) +{ + MEASUREMENT_FEATURE_USE * feature_use = NULL; + MEASUREMENT_GROUP * measurement_group = NULL; + CUSTOM_MEASUREMENT * custom_measurement = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the public API. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_REPORT); + + /***************************************************************************/ + /* Free all internal strings then the header itself. */ + /***************************************************************************/ + feature_use = dlist_pop_last(&event->feature_usage); + while (feature_use != NULL) + { + EVEL_DEBUG("Freeing Feature use Info (%s)", feature_use->feature_id); + free(feature_use->feature_id); + free(feature_use); + feature_use = dlist_pop_last(&event->feature_usage); + } + measurement_group = dlist_pop_last(&event->measurement_groups); + while (measurement_group != NULL) + { + EVEL_DEBUG("Freeing Measurement Group (%s)", measurement_group->name); + + custom_measurement = dlist_pop_last(&measurement_group->measurements); + while (custom_measurement != NULL) + { + EVEL_DEBUG("Freeing mesaurement (%s)", custom_measurement->name); + + free(custom_measurement->name); + free(custom_measurement->value); + free(custom_measurement); + custom_measurement = dlist_pop_last(&measurement_group->measurements); + } + + free(measurement_group->name); + free(measurement_group); + measurement_group = dlist_pop_last(&event->measurement_groups); + } + + evel_free_header(&event->header); + + EVEL_EXIT(); +} diff --git a/vnfs/VES/code/evel_library/evel_scaling_measurement.c b/vnfs/VES/code/evel_library/evel_scaling_measurement.c new file mode 100644 index 00000000..ec8f32a4 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_scaling_measurement.c @@ -0,0 +1,1711 @@ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the Measurement. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include + +#include "evel.h" +#include "evel_internal.h" +#include "evel_throttle.h" + +/**************************************************************************//** + * Create a new Measurement event. + * + * @note The mandatory fields on the Measurement must be supplied to this + * factory function and are immutable once set. Optional fields have + * explicit setter functions, but again values may only be set once so + * that the Measurement has immutable properties. + * + * @param measurement_interval + * + * @returns pointer to the newly manufactured ::EVENT_MEASUREMENT. If the + * event is not used (i.e. posted) it must be released using + * ::evel_free_event. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_MEASUREMENT * evel_new_measurement(double measurement_interval) +{ + EVENT_MEASUREMENT * measurement = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement_interval >= 0.0); + + /***************************************************************************/ + /* Allocate the measurement. */ + /***************************************************************************/ + measurement = malloc(sizeof(EVENT_MEASUREMENT)); + if (measurement == NULL) + { + log_error_state("Out of memory for Measurement"); + goto exit_label; + } + memset(measurement, 0, sizeof(EVENT_MEASUREMENT)); + EVEL_DEBUG("New measurement is at %lp", measurement); + + /***************************************************************************/ + /* Initialize the header & the measurement fields. */ + /***************************************************************************/ + evel_init_header(&measurement->header); + measurement->header.event_domain = EVEL_DOMAIN_MEASUREMENT; + measurement->measurement_interval = measurement_interval; + dlist_initialize(&measurement->cpu_usage); + dlist_initialize(&measurement->filesystem_usage); + dlist_initialize(&measurement->latency_distribution); + dlist_initialize(&measurement->vnic_usage); + dlist_initialize(&measurement->codec_usage); + dlist_initialize(&measurement->feature_usage); + dlist_initialize(&measurement->additional_measurements); + evel_init_option_double(&measurement->aggregate_cpu_usage); + evel_init_option_double(&measurement->mean_request_latency); + evel_init_option_double(&measurement->memory_configured); + evel_init_option_double(&measurement->memory_used); + evel_init_option_double(&measurement->vnfc_scaling_metric); + evel_init_option_int(&measurement->concurrent_sessions); + evel_init_option_int(&measurement->configured_entities); + evel_init_option_int(&measurement->media_ports_in_use); + evel_init_option_int(&measurement->request_rate); + measurement->major_version = EVEL_MEASUREMENT_MAJOR_VERSION; + measurement->minor_version = EVEL_MEASUREMENT_MINOR_VERSION; + +exit_label: + EVEL_EXIT(); + return measurement; +} + +/**************************************************************************//** + * Set the Event Type property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_measurement_type_set(EVENT_MEASUREMENT * measurement, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + evel_header_type_set(&measurement->header, type); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Concurrent Sessions property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param concurrent_sessions The Concurrent Sessions to be set. + *****************************************************************************/ +void evel_measurement_conc_sess_set(EVENT_MEASUREMENT * measurement, + int concurrent_sessions) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(concurrent_sessions >= 0); + + evel_set_option_int(&measurement->concurrent_sessions, + concurrent_sessions, + "Concurrent Sessions"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Configured Entities property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param configured_entities The Configured Entities to be set. + *****************************************************************************/ +void evel_measurement_cfg_ents_set(EVENT_MEASUREMENT * measurement, + int configured_entities) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(configured_entities >= 0); + + evel_set_option_int(&measurement->configured_entities, + configured_entities, + "Configured Entities"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an additional set of Errors to the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the measurement. + * @param receive_discards The number of receive discards. + * @param receive_errors The number of receive errors. + * @param transmit_discards The number of transmit discards. + * @param transmit_errors The number of transmit errors. + *****************************************************************************/ +void evel_measurement_errors_set(EVENT_MEASUREMENT * measurement, + int receive_discards, + int receive_errors, + int transmit_discards, + int transmit_errors) +{ + MEASUREMENT_ERRORS * errors = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(receive_discards >= 0); + assert(receive_errors >= 0); + assert(transmit_discards >= 0); + assert(transmit_errors >= 0); + + if (measurement->errors == NULL) + { + EVEL_DEBUG("Adding Errors: %d, %d; %d, %d", + receive_discards, + receive_errors, + transmit_discards, + transmit_errors); + errors = malloc(sizeof(MEASUREMENT_ERRORS)); + assert(errors != NULL); + memset(errors, 0, sizeof(MEASUREMENT_ERRORS)); + errors->receive_discards = receive_discards; + errors->receive_errors = receive_errors; + errors->transmit_discards = transmit_discards; + errors->transmit_errors = transmit_errors; + measurement->errors = errors; + } + else + { + errors = measurement->errors; + EVEL_DEBUG("Ignoring attempt to add Errors: %d, %d; %d, %d\n" + "Errors already set: %d, %d; %d, %d", + receive_discards, + receive_errors, + transmit_discards, + transmit_errors, + errors->receive_discards, + errors->receive_errors, + errors->transmit_discards, + errors->transmit_errors); + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Mean Request Latency property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param mean_request_latency The Mean Request Latency to be set. + *****************************************************************************/ +void evel_measurement_mean_req_lat_set(EVENT_MEASUREMENT * measurement, + double mean_request_latency) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(mean_request_latency >= 0.0); + + evel_set_option_double(&measurement->mean_request_latency, + mean_request_latency, + "Mean Request Latency"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Memory Configured property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param memory_configured The Memory Configured to be set. + *****************************************************************************/ +void evel_measurement_mem_cfg_set(EVENT_MEASUREMENT * measurement, + double memory_configured) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(memory_configured >= 0.0); + + evel_set_option_double(&measurement->memory_configured, + memory_configured, + "Memory Configured"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Memory Used property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param memory_used The Memory Used to be set. + *****************************************************************************/ +void evel_measurement_mem_used_set(EVENT_MEASUREMENT * measurement, + double memory_used) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(memory_used >= 0.0); + + evel_set_option_double(&measurement->memory_used, + memory_used, + "Memory Used"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Request Rate property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the Measurement. + * @param request_rate The Request Rate to be set. + *****************************************************************************/ +void evel_measurement_request_rate_set(EVENT_MEASUREMENT * measurement, + int request_rate) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(request_rate >= 0); + + evel_set_option_int(&measurement->request_rate, + request_rate, + "Request Rate"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an additional CPU usage value name/value pair to the Measurement. + * + * The name and value are null delimited ASCII strings. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param measurement Pointer to the measurement. + * @param id ASCIIZ string with the CPU's identifier. + * @param usage CPU utilization. + *****************************************************************************/ +void evel_measurement_cpu_use_add(EVENT_MEASUREMENT * measurement, + char * id, double usage) +{ + MEASUREMENT_CPU_USE * cpu_use = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(id != NULL); + assert(usage >= 0.0); + + /***************************************************************************/ + /* Allocate a container for the value and push onto the list. */ + /***************************************************************************/ + EVEL_DEBUG("Adding id=%s usage=%lf", id, usage); + cpu_use = malloc(sizeof(MEASUREMENT_CPU_USE)); + assert(cpu_use != NULL); + memset(cpu_use, 0, sizeof(MEASUREMENT_CPU_USE)); + cpu_use->id = strdup(id); + cpu_use->usage = usage; + assert(cpu_use->id != NULL); + + dlist_push_last(&measurement->cpu_usage, cpu_use); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an additional File System usage value name/value pair to the + * Measurement. + * + * The filesystem_name is null delimited ASCII string. The library takes a + * copy so the caller does not have to preserve values after the function + * returns. + * + * @param measurement Pointer to the measurement. + * @param filesystem_name ASCIIZ string with the file-system's UUID. + * @param block_configured Block storage configured. + * @param block_used Block storage in use. + * @param block_iops Block storage IOPS. + * @param ephemeral_configured Ephemeral storage configured. + * @param ephemeral_used Ephemeral storage in use. + * @param ephemeral_iops Ephemeral storage IOPS. + *****************************************************************************/ +void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement, + char * filesystem_name, + double block_configured, + double block_used, + int block_iops, + double ephemeral_configured, + double ephemeral_used, + int ephemeral_iops) +{ + MEASUREMENT_FSYS_USE * fsys_use = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(filesystem_name != NULL); + assert(block_configured >= 0.0); + assert(block_used >= 0.0); + assert(block_iops >= 0); + assert(ephemeral_configured >= 0.0); + assert(ephemeral_used >= 0.0); + assert(ephemeral_iops >= 0); + + /***************************************************************************/ + /* Allocate a container for the value and push onto the list. */ + /***************************************************************************/ + EVEL_DEBUG("Adding filesystem_name=%s", filesystem_name); + fsys_use = malloc(sizeof(MEASUREMENT_FSYS_USE)); + assert(fsys_use != NULL); + memset(fsys_use, 0, sizeof(MEASUREMENT_FSYS_USE)); + fsys_use->filesystem_name = strdup(filesystem_name); + fsys_use->block_configured = block_configured; + fsys_use->block_used = block_used; + fsys_use->block_iops = block_iops; + fsys_use->ephemeral_configured = block_configured; + fsys_use->ephemeral_used = ephemeral_used; + fsys_use->ephemeral_iops = ephemeral_iops; + + dlist_push_last(&measurement->filesystem_usage, fsys_use); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add a Feature usage value name/value pair to the Measurement. + * + * The name is null delimited ASCII string. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param measurement Pointer to the measurement. + * @param feature ASCIIZ string with the feature's name. + * @param utilization Utilization of the feature. + *****************************************************************************/ +void evel_measurement_feature_use_add(EVENT_MEASUREMENT * measurement, + char * feature, + int utilization) +{ + MEASUREMENT_FEATURE_USE * feature_use = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(feature != NULL); + assert(utilization >= 0); + + /***************************************************************************/ + /* Allocate a container for the value and push onto the list. */ + /***************************************************************************/ + EVEL_DEBUG("Adding Feature=%s Use=%d", feature, utilization); + feature_use = malloc(sizeof(MEASUREMENT_FEATURE_USE)); + assert(feature_use != NULL); + memset(feature_use, 0, sizeof(MEASUREMENT_FEATURE_USE)); + feature_use->feature_id = strdup(feature); + assert(feature_use->feature_id != NULL); + feature_use->feature_utilization = utilization; + + dlist_push_last(&measurement->feature_usage, feature_use); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add a Additional Measurement value name/value pair to the Report. + * + * The name is null delimited ASCII string. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param measurement Pointer to the Measaurement. + * @param group ASCIIZ string with the measurement group's name. + * @param name ASCIIZ string containing the measurement's name. + * @param value ASCIIZ string containing the measurement's value. + *****************************************************************************/ +void evel_measurement_custom_measurement_add(EVENT_MEASUREMENT * measurement, + const char * const group, + const char * const name, + const char * const value) +{ + MEASUREMENT_GROUP * measurement_group = NULL; + CUSTOM_MEASUREMENT * custom_measurement = NULL; + DLIST_ITEM * item = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(group != NULL); + assert(name != NULL); + assert(value != NULL); + + /***************************************************************************/ + /* Allocate a container for the name/value pair. */ + /***************************************************************************/ + EVEL_DEBUG("Adding Measurement Group=%s Name=%s Value=%s", + group, name, value); + custom_measurement = malloc(sizeof(CUSTOM_MEASUREMENT)); + assert(custom_measurement != NULL); + memset(custom_measurement, 0, sizeof(CUSTOM_MEASUREMENT)); + custom_measurement->name = strdup(name); + assert(custom_measurement->name != NULL); + custom_measurement->value = strdup(value); + assert(custom_measurement->value != NULL); + + /***************************************************************************/ + /* See if we have that group already. */ + /***************************************************************************/ + item = dlist_get_first(&measurement->additional_measurements); + while (item != NULL) + { + measurement_group = (MEASUREMENT_GROUP *) item->item; + assert(measurement_group != NULL); + + EVEL_DEBUG("Got measurement group %s", measurement_group->name); + if (strcmp(group, measurement_group->name) == 0) + { + EVEL_DEBUG("Found existing Measurement Group"); + break; + } + item = dlist_get_next(item); + } + + /***************************************************************************/ + /* If we didn't have the group already, create it. */ + /***************************************************************************/ + if (item == NULL) + { + EVEL_DEBUG("Creating new Measurement Group"); + measurement_group = malloc(sizeof(MEASUREMENT_GROUP)); + assert(measurement_group != NULL); + memset(measurement_group, 0, sizeof(MEASUREMENT_GROUP)); + measurement_group->name = strdup(group); + assert(measurement_group->name != NULL); + dlist_initialize(&measurement_group->measurements); + dlist_push_last(&measurement->additional_measurements, measurement_group); + } + + /***************************************************************************/ + /* If we didn't have the group already, create it. */ + /***************************************************************************/ + dlist_push_last(&measurement_group->measurements, custom_measurement); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add a Codec usage value name/value pair to the Measurement. + * + * The name is null delimited ASCII string. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param measurement Pointer to the measurement. + * @param codec ASCIIZ string with the codec's name. + * @param utilization Number of codecs in use. + *****************************************************************************/ +void evel_measurement_codec_use_add(EVENT_MEASUREMENT * measurement, + char * codec, + int utilization) +{ + MEASUREMENT_CODEC_USE * codec_use = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(codec != NULL); + assert(utilization >= 0.0); + + /***************************************************************************/ + /* Allocate a container for the value and push onto the list. */ + /***************************************************************************/ + EVEL_DEBUG("Adding Codec=%s Use=%d", codec, utilization); + codec_use = malloc(sizeof(MEASUREMENT_CODEC_USE)); + assert(codec_use != NULL); + memset(codec_use, 0, sizeof(MEASUREMENT_CODEC_USE)); + codec_use->codec_id = strdup(codec); + assert(codec_use->codec_id != NULL); + codec_use->number_in_use = utilization; + + dlist_push_last(&measurement->codec_usage, codec_use); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Aggregate CPU Use property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the measurement. + * @param cpu_use The CPU use to set. + *****************************************************************************/ +void evel_measurement_agg_cpu_use_set(EVENT_MEASUREMENT * measurement, + double cpu_use) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(cpu_use >= 0.0); + + evel_set_option_double(&measurement->aggregate_cpu_usage, + cpu_use, + "CPU Use"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Media Ports in Use property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the measurement. + * @param media_ports_in_use The media port usage to set. + *****************************************************************************/ +void evel_measurement_media_port_use_set(EVENT_MEASUREMENT * measurement, + int media_ports_in_use) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(media_ports_in_use >= 0); + + evel_set_option_int(&measurement->media_ports_in_use, + media_ports_in_use, + "Media Ports In Use"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the VNFC Scaling Metric property of the Measurement. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param measurement Pointer to the measurement. + * @param scaling_metric The scaling metric to set. + *****************************************************************************/ +void evel_measurement_vnfc_scaling_metric_set(EVENT_MEASUREMENT * measurement, + double scaling_metric) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(scaling_metric >= 0.0); + + evel_set_option_double(&measurement->vnfc_scaling_metric, + scaling_metric, + "VNFC Scaling Metric"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Create a new Latency Bucket to be added to a Measurement event. + * + * @note The mandatory fields on the ::MEASUREMENT_LATENCY_BUCKET must be + * supplied to this factory function and are immutable once set. + * Optional fields have explicit setter functions, but again values + * may only be set once so that the ::MEASUREMENT_LATENCY_BUCKET has + * immutable properties. + * + * @param count Count of events in this bucket. + * + * @returns pointer to the newly manufactured ::MEASUREMENT_LATENCY_BUCKET. + * If the structure is not used it must be released using free. + * @retval NULL Failed to create the Latency Bucket. + *****************************************************************************/ +MEASUREMENT_LATENCY_BUCKET * evel_new_meas_latency_bucket(const int count) +{ + MEASUREMENT_LATENCY_BUCKET * bucket; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(count >= 0); + + /***************************************************************************/ + /* Allocate, then set Mandatory Parameters. */ + /***************************************************************************/ + EVEL_DEBUG("Creating bucket, count = %d", count); + bucket = malloc(sizeof(MEASUREMENT_LATENCY_BUCKET)); + assert(bucket != NULL); + + /***************************************************************************/ + /* Set Mandatory Parameters. */ + /***************************************************************************/ + bucket->count = count; + + /***************************************************************************/ + /* Initialize Optional Parameters. */ + /***************************************************************************/ + evel_init_option_double(&bucket->high_end); + evel_init_option_double(&bucket->low_end); + + EVEL_EXIT(); + + return bucket; +} + +/**************************************************************************//** + * Set the High End property of the Measurement Latency Bucket. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param bucket Pointer to the Measurement Latency Bucket. + * @param high_end High end of the bucket's range. + *****************************************************************************/ +void evel_meas_latency_bucket_high_end_set( + MEASUREMENT_LATENCY_BUCKET * const bucket, + const double high_end) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(high_end >= 0.0); + evel_set_option_double(&bucket->high_end, high_end, "High End"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Low End property of the Measurement Latency Bucket. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param bucket Pointer to the Measurement Latency Bucket. + * @param low_end Low end of the bucket's range. + *****************************************************************************/ +void evel_meas_latency_bucket_low_end_set( + MEASUREMENT_LATENCY_BUCKET * const bucket, + const double low_end) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(low_end >= 0.0); + evel_set_option_double(&bucket->low_end, low_end, "Low End"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an additional Measurement Latency Bucket to the specified event. + * + * @param measurement Pointer to the Measurement event. + * @param bucket Pointer to the Measurement Latency Bucket to add. + *****************************************************************************/ +void evel_meas_latency_bucket_add(EVENT_MEASUREMENT * const measurement, + MEASUREMENT_LATENCY_BUCKET * const bucket) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(bucket != NULL); + dlist_push_last(&measurement->latency_distribution, bucket); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an additional Latency Distribution bucket to the Measurement. + * + * This function implements the previous API, purely for convenience. + * + * @param measurement Pointer to the measurement. + * @param low_end Low end of the bucket's range. + * @param high_end High end of the bucket's range. + * @param count Count of events in this bucket. + *****************************************************************************/ +void evel_measurement_latency_add(EVENT_MEASUREMENT * const measurement, + const double low_end, + const double high_end, + const int count) +{ + MEASUREMENT_LATENCY_BUCKET * bucket = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Trust the assertions in the underlying methods. */ + /***************************************************************************/ + bucket = evel_new_meas_latency_bucket(count); + evel_meas_latency_bucket_low_end_set(bucket, low_end); + evel_meas_latency_bucket_high_end_set(bucket, high_end); + evel_meas_latency_bucket_add(measurement, bucket); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Create a new vNIC Use to be added to a Measurement event. + * + * @note The mandatory fields on the ::MEASUREMENT_VNIC_USE must be supplied + * to this factory function and are immutable once set. Optional + * fields have explicit setter functions, but again values may only be + * set once so that the ::MEASUREMENT_VNIC_USE has immutable + * properties. + * + * @param vnic_id ASCIIZ string with the vNIC's ID. + * @param packets_in Total packets received. + * @param packets_out Total packets transmitted. + * @param bytes_in Total bytes received. + * @param bytes_out Total bytes transmitted. + * + * @returns pointer to the newly manufactured ::MEASUREMENT_VNIC_USE. + * If the structure is not used it must be released using + * ::evel_free_measurement_vnic_use. + * @retval NULL Failed to create the vNIC Use. + *****************************************************************************/ +MEASUREMENT_VNIC_USE * evel_new_measurement_vnic_use(char * const vnic_id, + const int packets_in, + const int packets_out, + const int bytes_in, + const int bytes_out) +{ + MEASUREMENT_VNIC_USE * vnic_use; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(vnic_id != NULL); + assert(packets_in >= 0); + assert(packets_out >= 0); + assert(bytes_in >= 0); + assert(bytes_out >= 0); + + /***************************************************************************/ + /* Allocate, then set Mandatory Parameters. */ + /***************************************************************************/ + EVEL_DEBUG("Adding VNIC ID=%s", vnic_id); + vnic_use = malloc(sizeof(MEASUREMENT_VNIC_USE)); + assert(vnic_use != NULL); + vnic_use->vnic_id = strdup(vnic_id); + vnic_use->packets_in = packets_in; + vnic_use->packets_out = packets_out; + vnic_use->bytes_in = bytes_in; + vnic_use->bytes_out = bytes_out; + + /***************************************************************************/ + /* Initialize Optional Parameters. */ + /***************************************************************************/ + evel_init_option_int(&vnic_use->broadcast_packets_in); + evel_init_option_int(&vnic_use->broadcast_packets_out); + evel_init_option_int(&vnic_use->multicast_packets_in); + evel_init_option_int(&vnic_use->multicast_packets_out); + evel_init_option_int(&vnic_use->unicast_packets_in); + evel_init_option_int(&vnic_use->unicast_packets_out); + + EVEL_EXIT(); + + return vnic_use; +} + +/**************************************************************************//** + * Free a vNIC Use. + * + * Free off the ::MEASUREMENT_VNIC_USE supplied. Will free all the contained + * allocated memory. + * + * @note It does not free the vNIC Use itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_measurement_vnic_use(MEASUREMENT_VNIC_USE * const vnic_use) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(vnic_use != NULL); + assert(vnic_use->vnic_id != NULL); + + /***************************************************************************/ + /* Free the duplicated string. */ + /***************************************************************************/ + free(vnic_use->vnic_id); + vnic_use->vnic_id = NULL; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Broadcast Packets Received property of the vNIC Use. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param vnic_use Pointer to the vNIC Use. + * @param broadcast_packets_in + * Broadcast packets received. + *****************************************************************************/ +void evel_vnic_use_bcast_pkt_in_set(MEASUREMENT_VNIC_USE * const vnic_use, + const int broadcast_packets_in) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(broadcast_packets_in >= 0); + + evel_set_option_int(&vnic_use->broadcast_packets_in, + broadcast_packets_in, + "Broadcast Packets Received"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Broadcast Packets Transmitted property of the vNIC Use. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param vnic_use Pointer to the vNIC Use. + * @param broadcast_packets_out + * Broadcast packets transmitted. + *****************************************************************************/ +void evel_vnic_use_bcast_pkt_out_set(MEASUREMENT_VNIC_USE * const vnic_use, + const int broadcast_packets_out) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(broadcast_packets_out >= 0); + + evel_set_option_int(&vnic_use->broadcast_packets_out, + broadcast_packets_out, + "Broadcast Packets Transmitted"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Multicast Packets Received property of the vNIC Use. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param vnic_use Pointer to the vNIC Use. + * @param multicast_packets_in + * Multicast packets received. + *****************************************************************************/ +void evel_vnic_use_mcast_pkt_in_set(MEASUREMENT_VNIC_USE * const vnic_use, + const int multicast_packets_in) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(multicast_packets_in >= 0); + + evel_set_option_int(&vnic_use->multicast_packets_in, + multicast_packets_in, + "Multicast Packets Received"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Multicast Packets Transmitted property of the vNIC Use. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param vnic_use Pointer to the vNIC Use. + * @param multicast_packets_out + * Multicast packets transmitted. + *****************************************************************************/ +void evel_vnic_use_mcast_pkt_out_set(MEASUREMENT_VNIC_USE * const vnic_use, + const int multicast_packets_out) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(multicast_packets_out >= 0); + + evel_set_option_int(&vnic_use->multicast_packets_out, + multicast_packets_out, + "Multicast Packets Transmitted"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Unicast Packets Received property of the vNIC Use. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param vnic_use Pointer to the vNIC Use. + * @param unicast_packets_in + * Unicast packets received. + *****************************************************************************/ +void evel_vnic_use_ucast_pkt_in_set(MEASUREMENT_VNIC_USE * const vnic_use, + const int unicast_packets_in) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(unicast_packets_in >= 0); + + evel_set_option_int(&vnic_use->unicast_packets_in, + unicast_packets_in, + "Unicast Packets Received"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Unicast Packets Transmitted property of the vNIC Use. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param vnic_use Pointer to the vNIC Use. + * @param unicast_packets_out + * Unicast packets transmitted. + *****************************************************************************/ +void evel_vnic_use_ucast_pkt_out_set(MEASUREMENT_VNIC_USE * const vnic_use, + const int unicast_packets_out) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(unicast_packets_out >= 0); + + evel_set_option_int(&vnic_use->unicast_packets_out, + unicast_packets_out, + "Unicast Packets Transmitted"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an additional vNIC Use to the specified Measurement event. + * + * @param measurement Pointer to the measurement. + * @param vnic_use Pointer to the vNIC Use to add. + *****************************************************************************/ +void evel_meas_vnic_use_add(EVENT_MEASUREMENT * const measurement, + MEASUREMENT_VNIC_USE * const vnic_use) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(vnic_use != NULL); + + dlist_push_last(&measurement->vnic_usage, vnic_use); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an additional vNIC usage record Measurement. + * + * This function implements the previous API, purely for convenience. + * + * The ID is null delimited ASCII string. The library takes a copy so the + * caller does not have to preserve values after the function returns. + * + * @param measurement Pointer to the measurement. + * @param vnic_id ASCIIZ string with the vNIC's ID. + * @param packets_in Total packets received. + * @param packets_out Total packets transmitted. + * @param broadcast_packets_in Broadcast packets received. + * @param broadcast_packets_out Broadcast packets transmitted. + * @param bytes_in Total bytes received. + * @param bytes_out Total bytes transmitted. + * @param multicast_packets_in Multicast packets received. + * @param multicast_packets_out Multicast packets transmitted. + * @param unicast_packets_in Unicast packets received. + * @param unicast_packets_out Unicast packets transmitted. + *****************************************************************************/ +void evel_measurement_vnic_use_add(EVENT_MEASUREMENT * const measurement, + char * const vnic_id, + const int packets_in, + const int packets_out, + const int broadcast_packets_in, + const int broadcast_packets_out, + const int bytes_in, + const int bytes_out, + const int multicast_packets_in, + const int multicast_packets_out, + const int unicast_packets_in, + const int unicast_packets_out) +{ + MEASUREMENT_VNIC_USE * vnic_use = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Trust the assertions in the underlying methods. */ + /***************************************************************************/ + vnic_use = evel_new_measurement_vnic_use(vnic_id, + packets_in, + packets_out, + bytes_in, + bytes_out); + evel_vnic_use_bcast_pkt_in_set(vnic_use, broadcast_packets_in); + evel_vnic_use_bcast_pkt_out_set(vnic_use, broadcast_packets_out); + evel_vnic_use_mcast_pkt_in_set(vnic_use, multicast_packets_in); + evel_vnic_use_mcast_pkt_out_set(vnic_use, multicast_packets_out); + evel_vnic_use_ucast_pkt_in_set(vnic_use, unicast_packets_in); + evel_vnic_use_ucast_pkt_out_set(vnic_use, unicast_packets_out); + evel_meas_vnic_use_add(measurement, vnic_use); +} + +/**************************************************************************//** + * Encode the measurement as a JSON measurement. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_measurement(EVEL_JSON_BUFFER * jbuf, + EVENT_MEASUREMENT * event) +{ + MEASUREMENT_CPU_USE * cpu_use = NULL; + MEASUREMENT_FSYS_USE * fsys_use = NULL; + MEASUREMENT_LATENCY_BUCKET * bucket = NULL; + MEASUREMENT_VNIC_USE * vnic_use = NULL; + MEASUREMENT_ERRORS * errors = NULL; + MEASUREMENT_FEATURE_USE * feature_use = NULL; + MEASUREMENT_CODEC_USE * codec_use = NULL; + MEASUREMENT_GROUP * measurement_group = NULL; + CUSTOM_MEASUREMENT * custom_measurement = NULL; + DLIST_ITEM * item = NULL; + DLIST_ITEM * nested_item = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + + evel_json_encode_header(jbuf, &event->header); + evel_json_open_named_object(jbuf, "measurementsForVfScalingFields"); + + /***************************************************************************/ + /* Mandatory fields. */ + /***************************************************************************/ + evel_enc_kv_double(jbuf, "measurementInterval", event->measurement_interval); + + /***************************************************************************/ + /* Optional fields. */ + /***************************************************************************/ + evel_enc_kv_opt_int(jbuf, "concurrentSessions", &event->concurrent_sessions); + evel_enc_kv_opt_int(jbuf, "configuredEntities", &event->configured_entities); + + /***************************************************************************/ + /* CPU Use list. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "cpuUsageArray")) + { + bool item_added = false; + + item = dlist_get_first(&event->cpu_usage); + while (item != NULL) + { + cpu_use = (MEASUREMENT_CPU_USE*) item->item; + assert(cpu_use != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "cpuUsageArray", + cpu_use->id)) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "cpuIdentifier", cpu_use->id); + evel_enc_kv_double(jbuf, "percentUsage", cpu_use->usage); + evel_json_close_object(jbuf); + item_added = true; + } + item = dlist_get_next(item); + } + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + if (!item_added) + { + evel_json_rewind(jbuf); + } + } + + /***************************************************************************/ + /* Filesystem Usage list. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "filesystemUsageArray")) + { + bool item_added = false; + + item = dlist_get_first(&event->filesystem_usage); + while (item != NULL) + { + fsys_use = (MEASUREMENT_FSYS_USE *) item->item; + assert(fsys_use != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "filesystemUsageArray", + fsys_use->filesystem_name)) + { + evel_json_open_object(jbuf); + evel_enc_kv_double( + jbuf, "blockConfigured", fsys_use->block_configured); + evel_enc_kv_int(jbuf, "blockIops", fsys_use->block_iops); + evel_enc_kv_double(jbuf, "blockUsed", fsys_use->block_used); + evel_enc_kv_double( + jbuf, "ephemeralConfigured", fsys_use->ephemeral_configured); + evel_enc_kv_int(jbuf, "ephemeralIops", fsys_use->ephemeral_iops); + evel_enc_kv_double(jbuf, "ephemeralUsed", fsys_use->ephemeral_used); + evel_enc_kv_string(jbuf, "filesystemName", fsys_use->filesystem_name); + evel_json_close_object(jbuf); + item_added = true; + } + item = dlist_get_next(item); + } + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + if (!item_added) + { + evel_json_rewind(jbuf); + } + } + + /***************************************************************************/ + /* Latency distribution. */ + /***************************************************************************/ + item = dlist_get_first(&event->latency_distribution); + if ((item != NULL) && + evel_json_open_opt_named_list(jbuf, "latencyDistribution")) + { + while (item != NULL) + { + bucket = (MEASUREMENT_LATENCY_BUCKET*) item->item; + assert(bucket != NULL); + + evel_json_open_object(jbuf); + evel_enc_kv_opt_double( + jbuf, "lowEndOfLatencyBucket", &bucket->low_end); + evel_enc_kv_opt_double( + jbuf, "highEndOfLatencyBucket", &bucket->high_end); + evel_enc_kv_int(jbuf, "countsInTheBucket", bucket->count); + evel_json_close_object(jbuf); + item = dlist_get_next(item); + } + evel_json_close_list(jbuf); + } + + evel_enc_kv_opt_double( + jbuf, "meanRequestLatency", &event->mean_request_latency); + evel_enc_kv_opt_double(jbuf, "memoryConfigured", &event->memory_configured); + evel_enc_kv_opt_double(jbuf, "memoryUsed", &event->memory_used); + evel_enc_kv_opt_int(jbuf, "requestRate", &event->request_rate); + + /***************************************************************************/ + /* vNIC Usage */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "vNicUsageArray")) + { + bool item_added = false; + + item = dlist_get_first(&event->vnic_usage); + while (item != NULL) + { + vnic_use = (MEASUREMENT_VNIC_USE *) item->item; + assert(vnic_use != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "vNicUsageArray", + vnic_use->vnic_id)) + { + evel_json_open_object(jbuf); + + /*********************************************************************/ + /* Mandatory fields. */ + /*********************************************************************/ + evel_enc_kv_int(jbuf, "bytesIn", vnic_use->bytes_in); + evel_enc_kv_int(jbuf, "bytesOut", vnic_use->bytes_out); + evel_enc_kv_int(jbuf, "packetsIn", vnic_use->packets_in); + evel_enc_kv_int(jbuf, "packetsOut", vnic_use->packets_out); + evel_enc_kv_string(jbuf, "vNicIdentifier", vnic_use->vnic_id); + + /*********************************************************************/ + /* Optional fields. */ + /*********************************************************************/ + evel_enc_kv_opt_int( + jbuf, "broadcastPacketsIn", &vnic_use->broadcast_packets_in); + evel_enc_kv_opt_int( + jbuf, "broadcastPacketsOut", &vnic_use->broadcast_packets_out); + evel_enc_kv_opt_int( + jbuf, "multicastPacketsIn", &vnic_use->multicast_packets_in); + evel_enc_kv_opt_int( + jbuf, "multicastPacketsOut", &vnic_use->multicast_packets_out); + evel_enc_kv_opt_int( + jbuf, "unicastPacketsIn", &vnic_use->unicast_packets_in); + evel_enc_kv_opt_int( + jbuf, "unicastPacketsOut", &vnic_use->unicast_packets_out); + + evel_json_close_object(jbuf); + item_added = true; + } + item = dlist_get_next(item); + } + + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + if (!item_added) + { + evel_json_rewind(jbuf); + } + } + + evel_enc_kv_opt_double( + jbuf, "aggregateCpuUsage", &event->aggregate_cpu_usage); + evel_enc_kv_opt_int( + jbuf, "numberOfMediaPortsInUse", &event->media_ports_in_use); + evel_enc_kv_opt_double( + jbuf, "vnfcScalingMetric", &event->vnfc_scaling_metric); + + /***************************************************************************/ + /* Errors list. */ + /***************************************************************************/ + if ((event->errors != NULL) && + evel_json_open_opt_named_object(jbuf, "errors")) + { + errors = event->errors; + evel_enc_kv_int(jbuf, "receiveDiscards", errors->receive_discards); + evel_enc_kv_int(jbuf, "receiveErrors", errors->receive_errors); + evel_enc_kv_int(jbuf, "transmitDiscards", errors->transmit_discards); + evel_enc_kv_int(jbuf, "transmitErrors", errors->transmit_errors); + evel_json_close_object(jbuf); + } + + /***************************************************************************/ + /* Feature Utilization list. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "featureUsageArray")) + { + bool item_added = false; + + item = dlist_get_first(&event->feature_usage); + while (item != NULL) + { + feature_use = (MEASUREMENT_FEATURE_USE*) item->item; + assert(feature_use != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "featureUsageArray", + feature_use->feature_id)) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "featureIdentifier", feature_use->feature_id); + evel_enc_kv_int( + jbuf, "featureUtilization", feature_use->feature_utilization); + evel_json_close_object(jbuf); + item_added = true; + } + item = dlist_get_next(item); + } + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + if (!item_added) + { + evel_json_rewind(jbuf); + } + } + + /***************************************************************************/ + /* Codec Utilization list. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "codecUsageArray")) + { + bool item_added = false; + + item = dlist_get_first(&event->codec_usage); + while (item != NULL) + { + codec_use = (MEASUREMENT_CODEC_USE*) item->item; + assert(codec_use != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "codecUsageArray", + codec_use->codec_id)) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "codecIdentifier", codec_use->codec_id); + evel_enc_kv_int(jbuf, "numberInUse", codec_use->number_in_use); + evel_json_close_object(jbuf); + item_added = true; + } + item = dlist_get_next(item); + } + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + if (!item_added) + { + evel_json_rewind(jbuf); + } + } + + /***************************************************************************/ + /* Additional Measurement Groups list. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "additionalMeasurements")) + { + bool item_added = false; + + item = dlist_get_first(&event->additional_measurements); + while (item != NULL) + { + measurement_group = (MEASUREMENT_GROUP *) item->item; + assert(measurement_group != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "additionalMeasurements", + measurement_group->name)) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "name", measurement_group->name); + evel_json_open_opt_named_list(jbuf, "measurements"); + + /*********************************************************************/ + /* Measurements list. */ + /*********************************************************************/ + nested_item = dlist_get_first(&measurement_group->measurements); + while (nested_item != NULL) + { + custom_measurement = (CUSTOM_MEASUREMENT *) nested_item->item; + assert(custom_measurement != NULL); + + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "name", custom_measurement->name); + evel_enc_kv_string(jbuf, "value", custom_measurement->value); + evel_json_close_object(jbuf); + nested_item = dlist_get_next(nested_item); + } + evel_json_close_list(jbuf); + evel_json_close_object(jbuf); + item_added = true; + } + item = dlist_get_next(item); + } + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + if (!item_added) + { + evel_json_rewind(jbuf); + } + } + + /***************************************************************************/ + /* Although optional, we always generate the version. Note that this */ + /* closes the object, too. */ + /***************************************************************************/ + evel_enc_version(jbuf, + "measurementsForVfScalingVersion", + event->major_version, + event->major_version); + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free a Measurement. + * + * Free off the Measurement supplied. Will free all the contained allocated + * memory. + * + * @note It does not free the Measurement itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_measurement(EVENT_MEASUREMENT * event) +{ + MEASUREMENT_CPU_USE * cpu_use = NULL; + MEASUREMENT_FSYS_USE * fsys_use = NULL; + MEASUREMENT_LATENCY_BUCKET * bucket = NULL; + MEASUREMENT_VNIC_USE * vnic_use = NULL; + MEASUREMENT_FEATURE_USE * feature_use = NULL; + MEASUREMENT_CODEC_USE * codec_use = NULL; + MEASUREMENT_GROUP * measurement_group = NULL; + CUSTOM_MEASUREMENT * measurement = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the public API. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + + /***************************************************************************/ + /* Free all internal strings then the header itself. */ + /***************************************************************************/ + cpu_use = dlist_pop_last(&event->cpu_usage); + while (cpu_use != NULL) + { + EVEL_DEBUG("Freeing CPU use Info (%s)", cpu_use->id); + free(cpu_use->id); + free(cpu_use); + cpu_use = dlist_pop_last(&event->cpu_usage); + } + + fsys_use = dlist_pop_last(&event->filesystem_usage); + while (fsys_use != NULL) + { + EVEL_DEBUG("Freeing Filesystem Use info (%s)", fsys_use->filesystem_name); + free(fsys_use->filesystem_name); + free(fsys_use); + fsys_use = dlist_pop_last(&event->filesystem_usage); + } + + bucket = dlist_pop_last(&event->latency_distribution); + while (bucket != NULL) + { + EVEL_DEBUG("Freeing Latency Bucket"); + free(bucket); + bucket = dlist_pop_last(&event->latency_distribution); + } + + vnic_use = dlist_pop_last(&event->vnic_usage); + while (vnic_use != NULL) + { + EVEL_DEBUG("Freeing vNIC use Info (%s)", vnic_use->vnic_id); + evel_free_measurement_vnic_use(vnic_use); + free(vnic_use); + vnic_use = dlist_pop_last(&event->vnic_usage); + } + + codec_use = dlist_pop_last(&event->codec_usage); + while (codec_use != NULL) + { + EVEL_DEBUG("Freeing Codec use Info (%s)", codec_use->codec_id); + free(codec_use->codec_id); + free(codec_use); + codec_use = dlist_pop_last(&event->codec_usage); + } + + if (event->errors != NULL) + { + EVEL_DEBUG("Freeing Errors"); + free(event->errors); + } + + feature_use = dlist_pop_last(&event->feature_usage); + while (feature_use != NULL) + { + EVEL_DEBUG("Freeing Feature use Info (%s)", feature_use->feature_id); + free(feature_use->feature_id); + free(feature_use); + feature_use = dlist_pop_last(&event->feature_usage); + } + + measurement_group = dlist_pop_last(&event->additional_measurements); + while (measurement_group != NULL) + { + EVEL_DEBUG("Freeing Measurement Group (%s)", measurement_group->name); + + measurement = dlist_pop_last(&measurement_group->measurements); + while (measurement != NULL) + { + EVEL_DEBUG("Freeing Measurement (%s)", measurement->name); + free(measurement->name); + free(measurement->value); + free(measurement); + measurement = dlist_pop_last(&measurement_group->measurements); + } + free(measurement_group->name); + free(measurement_group); + measurement_group = dlist_pop_last(&event->additional_measurements); + } + + evel_free_header(&event->header); + + EVEL_EXIT(); +} diff --git a/vnfs/VES/code/evel_library/evel_service.c b/vnfs/VES/code/evel_library/evel_service.c new file mode 100644 index 00000000..03699517 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_service.c @@ -0,0 +1,1313 @@ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to Service. + * + * License + * ------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include + +#include "evel_throttle.h" + +/**************************************************************************//** + * Create a new Service event. + * + * @note The mandatory fields on the Service must be supplied to + * this factory function and are immutable once set. Optional fields + * have explicit setter functions, but again values may only be set + * once so that the event has immutable properties. + * @param vendor_id The vendor id to encode in the event instance id. + * @param event_id The vendor event id to encode in the event instance id. + * @returns pointer to the newly manufactured ::EVENT_SERVICE. If the event + * is not used (i.e. posted) it must be released using + * ::evel_free_service. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_SERVICE * evel_new_service(const char * const vendor_id, + const char * const event_id) +{ + EVENT_SERVICE * event = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(vendor_id != NULL); + assert(event_id != NULL); + + /***************************************************************************/ + /* Allocate the Service event. */ + /***************************************************************************/ + event = malloc(sizeof(EVENT_SERVICE)); + if (event == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(event, 0, sizeof(EVENT_SERVICE)); + EVEL_DEBUG("New Service event is at %lp", event); + + /***************************************************************************/ + /* Initialize the header & the Service fields. */ + /***************************************************************************/ + evel_init_header(&event->header); + event->header.event_domain = EVEL_DOMAIN_SERVICE; + event->major_version = EVEL_SERVICE_MAJOR_VERSION; + event->minor_version = EVEL_SERVICE_MINOR_VERSION; + evel_init_event_instance_id(&event->instance_id, vendor_id, event_id); + evel_init_option_string(&event->correlator); + dlist_initialize(&event->additional_fields); + evel_init_option_string(&event->codec); + evel_init_option_string(&event->callee_side_codec); + evel_init_option_string(&event->caller_side_codec); + evel_init_option_string(&event->rtcp_data); + evel_init_option_string(&event->adjacency_name); + evel_init_option_string(&event->endpoint_description); + evel_init_option_int(&event->endpoint_jitter); + evel_init_option_int(&event->endpoint_rtp_oct_disc); + evel_init_option_int(&event->endpoint_rtp_oct_recv); + evel_init_option_int(&event->endpoint_rtp_oct_sent); + evel_init_option_int(&event->endpoint_rtp_pkt_disc); + evel_init_option_int(&event->endpoint_rtp_pkt_recv); + evel_init_option_int(&event->endpoint_rtp_pkt_sent); + evel_init_option_int(&event->local_jitter); + evel_init_option_int(&event->local_rtp_oct_disc); + evel_init_option_int(&event->local_rtp_oct_recv); + evel_init_option_int(&event->local_rtp_oct_sent); + evel_init_option_int(&event->local_rtp_pkt_disc); + evel_init_option_int(&event->local_rtp_pkt_recv); + evel_init_option_int(&event->local_rtp_pkt_sent); + evel_init_option_double(&event->mos_cqe); + evel_init_option_int(&event->packets_lost); + evel_init_option_double(&event->packet_loss_percent); + evel_init_option_int(&event->r_factor); + evel_init_option_int(&event->round_trip_delay); + evel_init_option_string(&event->phone_number); + +exit_label: + + EVEL_EXIT(); + return event; +} + +/**************************************************************************//** + * Set the Event Type property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_service_type_set(EVENT_SERVICE * const event, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_header_type_set(&event->header, type); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add a name/value pair to the Service, under the additionalFields array. + * + * The name and value are null delimited ASCII strings. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param event Pointer to the Service event. + * @param name ASCIIZ string with the field's name. The caller does not + * need to preserve the value once the function returns. + * @param value ASCIIZ string with the field's value. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_service_addl_field_add(EVENT_SERVICE * const event, + const char * const name, + const char * const value) +{ + OTHER_FIELD * nv_pair = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + assert(name != NULL); + assert(value != NULL); + + EVEL_DEBUG("Adding name=%s value=%s", name, value); + nv_pair = malloc(sizeof(OTHER_FIELD)); + assert(nv_pair != NULL); + nv_pair->name = strdup(name); + nv_pair->value = strdup(value); + assert(nv_pair->name != NULL); + assert(nv_pair->value != NULL); + + dlist_push_last(&event->additional_fields, nv_pair); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Product Id property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param product_id The vendor product id to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_service_product_id_set(EVENT_SERVICE * const event, + const char * const product_id) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_string(&event->instance_id.product_id, + product_id, + "Product Id"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Subsystem Id property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param subsystem_id The vendor subsystem id to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_service_subsystem_id_set(EVENT_SERVICE * const event, + const char * const subsystem_id) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_string(&event->instance_id.subsystem_id, + subsystem_id, + "Subsystem Id"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Friendly Name property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param friendly_name The vendor friendly name to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_service_friendly_name_set(EVENT_SERVICE * const event, + const char * const friendly_name) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_string(&event->instance_id.event_friendly_name, + friendly_name, + "Friendly Name"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Correlator property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param correlator The correlator to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_service_correlator_set(EVENT_SERVICE * const event, + const char * const correlator) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_string(&event->correlator, + correlator, + "Correlator"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Codec property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param codec The codec to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_service_codec_set(EVENT_SERVICE * const event, + const char * const codec) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_string(&event->codec, + codec, + "Codec"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Callee Side Codec property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param codec The codec to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_service_callee_codec_set(EVENT_SERVICE * const event, + const char * const codec) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_string(&event->callee_side_codec, + codec, + "Callee Side Codec"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Caller Side Codec property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param codec The codec to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_service_caller_codec_set(EVENT_SERVICE * const event, + const char * const codec) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_string(&event->caller_side_codec, + codec, + "Caller Side Codec"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the RTCP Data property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtcp_data The RTCP Data to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_service_rtcp_data_set(EVENT_SERVICE * const event, + const char * const rtcp_data) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_string(&event->rtcp_data, + rtcp_data, + "RTCP Data"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Adjacency Name property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param adjacency_name + * The adjacency name to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_service_adjacency_name_set(EVENT_SERVICE * const event, + const char * const adjacency_name) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_string(&event->adjacency_name, + adjacency_name, + "Adjacency Name"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Endpoint Descriptor property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param endpoint_desc The endpoint descriptor to be set. + *****************************************************************************/ +void evel_service_endpoint_desc_set( + EVENT_SERVICE * const event, + const EVEL_SERVICE_ENDPOINT_DESC endpoint_desc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_string(&event->endpoint_description, + evel_service_endpoint_desc(endpoint_desc), + "Endpoint Description"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Endpoint Jitter property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param jitter The jitter to be set. + *****************************************************************************/ +void evel_service_endpoint_jitter_set(EVENT_SERVICE * const event, + const int jitter) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->endpoint_jitter, + jitter, + "Endpoint Jitter"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Endpoint Rtp Octets Discarded property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_oct_disc The discard count. + *****************************************************************************/ +void evel_service_endpoint_rtp_oct_disc_set(EVENT_SERVICE * const event, + const int rtp_oct_disc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->endpoint_rtp_oct_disc, + rtp_oct_disc, + "Endpoint Rtp Octets Discarded"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Endpoint Rtp Octets Received property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_oct_recv The receive count. + *****************************************************************************/ +void evel_service_endpoint_rtp_oct_recv_set(EVENT_SERVICE * const event, + const int rtp_oct_recv) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->endpoint_rtp_oct_recv, + rtp_oct_recv, + "Endpoint Rtp Octets Received"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Endpoint Rtp Octets Sent property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_oct_sent The send count. + *****************************************************************************/ +void evel_service_endpoint_rtp_oct_sent_set(EVENT_SERVICE * const event, + const int rtp_oct_sent) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->endpoint_rtp_oct_sent, + rtp_oct_sent, + "Endpoint Rtp Octets Sent"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Endpoint Rtp Packets Discarded property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_pkt_disc The discard count. + *****************************************************************************/ +void evel_service_endpoint_rtp_pkt_disc_set(EVENT_SERVICE * const event, + const int rtp_pkt_disc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->endpoint_rtp_pkt_disc, + rtp_pkt_disc, + "Endpoint Rtp Packets Discarded"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Endpoint Rtp Packets Received property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_pkt_recv The receive count. + *****************************************************************************/ +void evel_service_endpoint_rtp_pkt_recv_set(EVENT_SERVICE * const event, + const int rtp_pkt_recv) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->endpoint_rtp_pkt_recv, + rtp_pkt_recv, + "Endpoint Rtp Packets Received"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Endpoint Rtp Packets Sent property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_pkt_sent The send count. + *****************************************************************************/ +void evel_service_endpoint_rtp_pkt_sent_set(EVENT_SERVICE * const event, + const int rtp_pkt_sent) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->endpoint_rtp_pkt_sent, + rtp_pkt_sent, + "Endpoint Rtp Packets Sent"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Local Jitter property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param jitter The jitter to be set. + *****************************************************************************/ +void evel_service_local_jitter_set(EVENT_SERVICE * const event, + const int jitter) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->local_jitter, + jitter, + "Local Jitter"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Local Rtp Octets Discarded property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_oct_disc The discard count. + *****************************************************************************/ +void evel_service_local_rtp_oct_disc_set(EVENT_SERVICE * const event, + const int rtp_oct_disc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->local_rtp_oct_disc, + rtp_oct_disc, + "Local Rtp Octets Discarded"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Local Rtp Octets Received property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_oct_recv The receive count. + *****************************************************************************/ +void evel_service_local_rtp_oct_recv_set(EVENT_SERVICE * const event, + const int rtp_oct_recv) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->local_rtp_oct_recv, + rtp_oct_recv, + "Local Rtp Octets Received"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Local Rtp Octets Sent property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_oct_sent The send count. + *****************************************************************************/ +void evel_service_local_rtp_oct_sent_set(EVENT_SERVICE * const event, + const int rtp_oct_sent) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->local_rtp_oct_sent, + rtp_oct_sent, + "Local Rtp Octets Sent"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Local Rtp Packets Discarded property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_pkt_disc The discard count. + *****************************************************************************/ +void evel_service_local_rtp_pkt_disc_set(EVENT_SERVICE * const event, + const int rtp_pkt_disc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->local_rtp_pkt_disc, + rtp_pkt_disc, + "Local Rtp Packets Discarded"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Local Rtp Packets Received property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_pkt_recv The receive count. + *****************************************************************************/ +void evel_service_local_rtp_pkt_recv_set(EVENT_SERVICE * const event, + const int rtp_pkt_recv) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->local_rtp_pkt_recv, + rtp_pkt_recv, + "Local Rtp Packets Received"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Local Rtp Packets Sent property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param rtp_pkt_sent The send count. + *****************************************************************************/ +void evel_service_local_rtp_pkt_sent_set(EVENT_SERVICE * const event, + const int rtp_pkt_sent) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->local_rtp_pkt_sent, + rtp_pkt_sent, + "Local Rtp Packets Sent"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Mos Cqe property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param mos_cqe The mosCqe to be set. + *****************************************************************************/ +void evel_service_mos_cqe_set(EVENT_SERVICE * const event, + const double mos_cqe) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_double(&event->mos_cqe, + mos_cqe, + "Mos Cqe"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Packets Lost property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param packets_lost The number of packets lost to be set. + *****************************************************************************/ +void evel_service_packets_lost_set(EVENT_SERVICE * const event, + const int packets_lost) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->packets_lost, + packets_lost, + "Packets Lost"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the packet Loss Percent property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param packet_loss_percent + * The packet loss in percent. + *****************************************************************************/ +void evel_service_packet_loss_percent_set(EVENT_SERVICE * const event, + const double packet_loss_percent) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_double(&event->packet_loss_percent, + packet_loss_percent, + "Packet Loss Percent"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the R Factor property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param r_factor The R Factor to be set. + *****************************************************************************/ +void evel_service_r_factor_set(EVENT_SERVICE * const event, + const int r_factor) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->r_factor, + r_factor, + "R Factor"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Round Trip Delay property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param round_trip_delay + * The Round trip delay to be set. + *****************************************************************************/ +void evel_service_round_trip_delay_set(EVENT_SERVICE * const event, + const int round_trip_delay) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_int(&event->round_trip_delay, + round_trip_delay, + "Round Trip Delay"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Phone Number property of the Service event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Service event. + * @param phone_number The Phone Number to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_service_phone_number_set(EVENT_SERVICE * const event, + const char * const phone_number) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + evel_set_option_string(&event->phone_number, + phone_number, + "Phone Number"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the Service in JSON according to AT&T's schema for the + * event type. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_service(EVEL_JSON_BUFFER * const jbuf, + EVENT_SERVICE * const event) +{ + OTHER_FIELD * nv_pair = NULL; + DLIST_ITEM * dlist_item = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + + evel_json_encode_header(jbuf, &event->header); + evel_json_open_named_object(jbuf, "serviceEventsFields"); + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + evel_json_encode_instance_id(jbuf, &event->instance_id); + evel_enc_version(jbuf, + "serviceEventsFieldsVersion", + event->major_version, + event->minor_version); + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + evel_enc_kv_opt_string(jbuf, "correlator", &event->correlator); + + /***************************************************************************/ + /* Checkpoint, so that we can wind back if all fields are suppressed. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "additionalFields")) + { + bool added = false; + + dlist_item = dlist_get_first(&event->additional_fields); + while (dlist_item != NULL) + { + nv_pair = (OTHER_FIELD *) dlist_item->item; + assert(nv_pair != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "additionalFields", + nv_pair->name)) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "name", nv_pair->name); + evel_enc_kv_string(jbuf, "value", nv_pair->value); + evel_json_close_object(jbuf); + added = true; + } + dlist_item = dlist_get_next(dlist_item); + } + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + if (!added) + { + evel_json_rewind(jbuf); + } + } + + /***************************************************************************/ + /* Optional fields within JSON equivalent object: codecSelected */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_object(jbuf, "codecSelected")) + { + bool added = false; + added |= evel_enc_kv_opt_string(jbuf, + "codec", + &event->codec); + evel_json_close_object(jbuf); + + /*************************************************************************/ + /* If the object is empty, rewind to before we opened it. */ + /*************************************************************************/ + if (!added) + { + evel_json_rewind(jbuf); + } + } + + /***************************************************************************/ + /* Optional fields within JSON equivalent object: codecSelectedTranscoding */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_object(jbuf, "codecSelectedTranscoding")) + { + bool added = false; + added |= evel_enc_kv_opt_string(jbuf, + "calleeSideCodec", + &event->callee_side_codec); + added |= evel_enc_kv_opt_string(jbuf, + "callerSideCodec", + &event->caller_side_codec); + evel_json_close_object(jbuf); + + /*************************************************************************/ + /* If the object is empty, rewind to before we opened it. */ + /*************************************************************************/ + if (!added) + { + evel_json_rewind(jbuf); + } + } + + /***************************************************************************/ + /* Optional fields within JSON equivalent object: midCallRtcp */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_object(jbuf, "midCallRtcp")) + { + bool added = false; + added |= evel_enc_kv_opt_string(jbuf, + "rtcpData", + &event->rtcp_data); + evel_json_close_object(jbuf); + + /*************************************************************************/ + /* If the object is empty, rewind to before we opened it. */ + /*************************************************************************/ + if (!added) + { + evel_json_rewind(jbuf); + } + } + + /***************************************************************************/ + /* Optional fields within JSON equivalent object: endOfCallVqmSummaries */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_object(jbuf, "endOfCallVqmSummaries")) + { + bool added = false; + added |= evel_enc_kv_opt_string(jbuf, + "adjacencyName", + &event->adjacency_name); + added |= evel_enc_kv_opt_string(jbuf, + "endpointDescription", + &event->endpoint_description); + added |= evel_enc_kv_opt_int(jbuf, + "endpointJitter", + &event->endpoint_jitter); + added |= evel_enc_kv_opt_int(jbuf, + "endpointRtpOctetsDiscarded", + &event->endpoint_rtp_oct_disc); + added |= evel_enc_kv_opt_int(jbuf, + "endpointRtpOctetsReceived", + &event->endpoint_rtp_oct_recv); + added |= evel_enc_kv_opt_int(jbuf, + "endpointRtpOctetsSent", + &event->endpoint_rtp_oct_sent); + added |= evel_enc_kv_opt_int(jbuf, + "endpointRtpPacketsDiscarded", + &event->endpoint_rtp_pkt_disc); + added |= evel_enc_kv_opt_int(jbuf, + "endpointRtpPacketsReceived", + &event->endpoint_rtp_pkt_recv); + added |= evel_enc_kv_opt_int(jbuf, + "endpointRtpPacketsSent", + &event->endpoint_rtp_pkt_sent); + added |= evel_enc_kv_opt_int(jbuf, + "localJitter", + &event->local_jitter); + added |= evel_enc_kv_opt_int(jbuf, + "localRtpOctetsDiscarded", + &event->local_rtp_oct_disc); + added |= evel_enc_kv_opt_int(jbuf, + "localRtpOctetsReceived", + &event->local_rtp_oct_recv); + added |= evel_enc_kv_opt_int(jbuf, + "localRtpOctetsSent", + &event->local_rtp_oct_sent); + added |= evel_enc_kv_opt_int(jbuf, + "localRtpPacketsDiscarded", + &event->local_rtp_pkt_disc); + added |= evel_enc_kv_opt_int(jbuf, + "localRtpPacketsReceived", + &event->local_rtp_pkt_recv); + added |= evel_enc_kv_opt_int(jbuf, + "localRtpPacketsSent", + &event->local_rtp_pkt_sent); + added |= evel_enc_kv_opt_double(jbuf, + "mosCqe", + &event->mos_cqe); + added |= evel_enc_kv_opt_int(jbuf, + "packetsLost", + &event->packets_lost); + added |= evel_enc_kv_opt_double(jbuf, + "packetLossPercent", + &event->packet_loss_percent); + added |= evel_enc_kv_opt_int(jbuf, + "rFactor", + &event->r_factor); + added |= evel_enc_kv_opt_int(jbuf, + "roundTripDelay", + &event->round_trip_delay); + evel_json_close_object(jbuf); + + /*************************************************************************/ + /* If the object is empty, rewind to before we opened it. */ + /*************************************************************************/ + if (!added) + { + evel_json_rewind(jbuf); + } + } + + /***************************************************************************/ + /* Optional fields within JSON equivalent object: marker */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_object(jbuf, "marker")) + { + bool added = false; + added |= evel_enc_kv_opt_string(jbuf, "phoneNumber", &event->phone_number); + evel_json_close_object(jbuf); + + /*************************************************************************/ + /* If the object is empty, rewind to before we opened it. */ + /*************************************************************************/ + if (!added) + { + evel_json_rewind(jbuf); + } + } + + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free a Service event. + * + * Free off the event supplied. Will free all the contained allocated memory. + * + * @note It does not free the event itself, since that may be part of a larger + * structure. + *****************************************************************************/ +void evel_free_service(EVENT_SERVICE * const event) +{ + OTHER_FIELD * nv_pair = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SERVICE); + + /***************************************************************************/ + /* Free all internal strings then the header itself. */ + /***************************************************************************/ + nv_pair = dlist_pop_last(&event->additional_fields); + while (nv_pair != NULL) + { + EVEL_DEBUG("Freeing Other Field (%s, %s)", nv_pair->name, nv_pair->value); + free(nv_pair->name); + free(nv_pair->value); + free(nv_pair); + nv_pair = dlist_pop_last(&event->additional_fields); + } + evel_free_option_string(&event->correlator); + evel_free_option_string(&event->codec); + evel_free_option_string(&event->callee_side_codec); + evel_free_option_string(&event->caller_side_codec); + evel_free_option_string(&event->rtcp_data); + evel_free_option_string(&event->adjacency_name); + evel_free_option_string(&event->endpoint_description); + evel_free_option_string(&event->phone_number); + evel_free_event_instance_id(&event->instance_id); + evel_free_header(&event->header); + + EVEL_EXIT(); +} diff --git a/vnfs/VES/code/evel_library/evel_signaling.c b/vnfs/VES/code/evel_library/evel_signaling.c new file mode 100644 index 00000000..102e89ef --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_signaling.c @@ -0,0 +1,509 @@ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to Signaling. + * + * License + * ------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include + +#include "evel_throttle.h" + +/**************************************************************************//** + * Create a new Signaling event. + * + * @note The mandatory fields on the Signaling must be supplied to + * this factory function and are immutable once set. Optional fields + * have explicit setter functions, but again values may only be set + * once so that the event has immutable properties. + * @param vendor_id The vendor id to encode in the event instance id. + * @param event_id The vendor event id to encode in the event instance id. + * @returns pointer to the newly manufactured ::EVENT_SIGNALING. If the event + * is not used (i.e. posted) it must be released using + * ::evel_free_signaling. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_SIGNALING * evel_new_signaling(const char * const vendor_id, + const char * const event_id) +{ + EVENT_SIGNALING * event = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(vendor_id != NULL); + assert(event_id != NULL); + + /***************************************************************************/ + /* Allocate the Signaling event. */ + /***************************************************************************/ + event = malloc(sizeof(EVENT_SIGNALING)); + if (event == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(event, 0, sizeof(EVENT_SIGNALING)); + EVEL_DEBUG("New Signaling event is at %lp", event); + + /***************************************************************************/ + /* Initialize the header & the Signaling fields. */ + /***************************************************************************/ + evel_init_header(&event->header); + event->header.event_domain = EVEL_DOMAIN_SIGNALING; + event->major_version = EVEL_SIGNALING_MAJOR_VERSION; + event->minor_version = EVEL_SIGNALING_MINOR_VERSION; + evel_init_event_instance_id(&event->instance_id, vendor_id, event_id); + evel_init_option_string(&event->correlator); + evel_init_option_string(&event->local_ip_address); + evel_init_option_string(&event->local_port); + evel_init_option_string(&event->remote_ip_address); + evel_init_option_string(&event->remote_port); + evel_init_option_string(&event->compressed_sip); + evel_init_option_string(&event->summary_sip); + +exit_label: + + EVEL_EXIT(); + return event; +} + +/**************************************************************************//** + * Set the Event Type property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_type_set(EVENT_SIGNALING * const event, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + evel_header_type_set(&event->header, type); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Local Ip Address property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param local_ip_address + * The Local Ip Address to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_signaling_local_ip_address_set(EVENT_SIGNALING * const event, + const char * const local_ip_address) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + assert(local_ip_address != NULL); + + evel_set_option_string(&event->local_ip_address, + local_ip_address, + "Local Ip Address"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Local Port property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param local_port The Local Port to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_local_port_set(EVENT_SIGNALING * const event, + const char * const local_port) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + assert(local_port != NULL); + + evel_set_option_string(&event->local_port, + local_port, + "Local Port"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Remote Ip Address property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param remote_ip_address + * The Remote Ip Address to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_signaling_remote_ip_address_set(EVENT_SIGNALING * const event, + const char * const remote_ip_address) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + assert(remote_ip_address != NULL); + + evel_set_option_string(&event->remote_ip_address, + remote_ip_address, + "Remote Ip Address"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Remote Port property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param remote_port The Remote Port to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_remote_port_set(EVENT_SIGNALING * const event, + const char * const remote_port) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + assert(remote_port != NULL); + + evel_set_option_string(&event->remote_port, + remote_port, + "Remote Port"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Compressed SIP property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param compressed_sip + * The Compressed SIP to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_compressed_sip_set(EVENT_SIGNALING * const event, + const char * const compressed_sip) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + assert(compressed_sip != NULL); + + evel_set_option_string(&event->compressed_sip, + compressed_sip, + "Compressed SIP"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Summary SIP property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param summary_sip The Summary SIP to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_summary_sip_set(EVENT_SIGNALING * const event, + const char * const summary_sip) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + assert(summary_sip != NULL); + + evel_set_option_string(&event->summary_sip, + summary_sip, + "Summary SIP"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Product Id property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param product_id The vendor product id to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_signaling_product_id_set(EVENT_SIGNALING * const event, + const char * const product_id) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + evel_set_option_string(&event->instance_id.product_id, + product_id, + "Product Id"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Subsystem Id property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param subsystem_id The vendor subsystem id to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_signaling_subsystem_id_set(EVENT_SIGNALING * const event, + const char * const subsystem_id) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + evel_set_option_string(&event->instance_id.subsystem_id, + subsystem_id, + "Subsystem Id"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Friendly Name property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param friendly_name The vendor friendly name to be set. ASCIIZ string. The + * caller does not need to preserve the value once the + * function returns. + *****************************************************************************/ +void evel_signaling_friendly_name_set(EVENT_SIGNALING * const event, + const char * const friendly_name) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + evel_set_option_string(&event->instance_id.event_friendly_name, + friendly_name, + "Friendly Name"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Correlator property of the Signaling event. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param event Pointer to the Signaling event. + * @param correlator The correlator to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_correlator_set(EVENT_SIGNALING * const event, + const char * const correlator) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + evel_set_option_string(&event->correlator, + correlator, + "Correlator"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the Signaling in JSON according to AT&T's schema for the + * event type. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_signaling(EVEL_JSON_BUFFER * const jbuf, + EVENT_SIGNALING * const event) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + + evel_json_encode_header(jbuf, &event->header); + evel_json_open_named_object(jbuf, "signalingFields"); + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + evel_json_encode_instance_id(jbuf, &event->instance_id); + evel_enc_version(jbuf, + "signalingFieldsVersion", + event->major_version, + event->minor_version); + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + evel_enc_kv_opt_string(jbuf, "correlator", &event->correlator); + evel_enc_kv_opt_string(jbuf, "localIpAddress", &event->local_ip_address); + evel_enc_kv_opt_string(jbuf, "localPort", &event->local_port); + evel_enc_kv_opt_string(jbuf, "remoteIpAddress", &event->remote_ip_address); + evel_enc_kv_opt_string(jbuf, "remotePort", &event->remote_port); + evel_enc_kv_opt_string(jbuf, "compressedSip", &event->compressed_sip); + evel_enc_kv_opt_string(jbuf, "summarySip", &event->summary_sip); + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free a Signaling event. + * + * Free off the event supplied. Will free all the contained allocated memory. + * + * @note It does not free the event itself, since that may be part of a larger + * structure. + *****************************************************************************/ +void evel_free_signaling(EVENT_SIGNALING * const event) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the public API. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING); + + evel_free_header(&event->header); + evel_free_event_instance_id(&event->instance_id); + evel_free_option_string(&event->correlator); + evel_free_option_string(&event->local_ip_address); + evel_free_option_string(&event->local_port); + evel_free_option_string(&event->remote_ip_address); + evel_free_option_string(&event->remote_port); + evel_free_option_string(&event->compressed_sip); + evel_free_option_string(&event->summary_sip); + + EVEL_EXIT(); +} diff --git a/vnfs/VES/code/evel_library/evel_state_change.c b/vnfs/VES/code/evel_library/evel_state_change.c new file mode 100644 index 00000000..4b4671d6 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_state_change.c @@ -0,0 +1,295 @@ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the State Change. + * + * License + * ------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include + +#include "evel_throttle.h" + +/**************************************************************************//** + * Create a new State Change event. + * + * @note The mandatory fields on the State Change must be supplied to this + * factory function and are immutable once set. Optional fields have + * explicit setter functions, but again values may only be set once + * so that the State Change has immutable properties. + * + * @param new_state The new state of the reporting entity. + * @param old_state The old state of the reporting entity. + * @param interface The card or port name of the reporting entity. + * + * @returns pointer to the newly manufactured ::EVENT_STATE_CHANGE. If the + * event is not used it must be released using + * ::evel_free_state_change + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_STATE_CHANGE * evel_new_state_change(const EVEL_ENTITY_STATE new_state, + const EVEL_ENTITY_STATE old_state, + const char * const interface) +{ + EVENT_STATE_CHANGE * state_change = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(new_state < EVEL_MAX_ENTITY_STATES); + assert(old_state < EVEL_MAX_ENTITY_STATES); + assert(interface != NULL); + + /***************************************************************************/ + /* Allocate the State Change. */ + /***************************************************************************/ + state_change = malloc(sizeof(EVENT_STATE_CHANGE)); + if (state_change == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(state_change, 0, sizeof(EVENT_STATE_CHANGE)); + EVEL_DEBUG("New State Change is at %lp", state_change); + + /***************************************************************************/ + /* Initialize the header & the State Change fields. Optional string */ + /* values are uninitialized (NULL). */ + /***************************************************************************/ + evel_init_header(&state_change->header); + state_change->header.event_domain = EVEL_DOMAIN_STATE_CHANGE; + state_change->major_version = EVEL_STATE_CHANGE_MAJOR_VERSION; + state_change->minor_version = EVEL_STATE_CHANGE_MINOR_VERSION; + state_change->new_state = new_state; + state_change->old_state = old_state; + state_change->state_interface = strdup(interface); + dlist_initialize(&state_change->additional_fields); + +exit_label: + EVEL_EXIT(); + return state_change; +} + +/**************************************************************************//** + * Free a State Change. + * + * Free off the State Change supplied. Will free all the contained allocated + * memory. + * + * @note It does not free the State Change itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_state_change(EVENT_STATE_CHANGE * const state_change) +{ + STATE_CHANGE_ADDL_FIELD * addl_field = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the public API. */ + /***************************************************************************/ + assert(state_change != NULL); + assert(state_change->header.event_domain == EVEL_DOMAIN_STATE_CHANGE); + + /***************************************************************************/ + /* Free all internal strings then the header itself. */ + /***************************************************************************/ + addl_field = dlist_pop_last(&state_change->additional_fields); + while (addl_field != NULL) + { + EVEL_DEBUG("Freeing Additional Field (%s, %s)", + addl_field->name, + addl_field->value); + free(addl_field->name); + free(addl_field->value); + free(addl_field); + addl_field = dlist_pop_last(&state_change->additional_fields); + } + free(state_change->state_interface); + evel_free_header(&state_change->header); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Event Type property of the State Change. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param state_change Pointer to the ::EVENT_STATE_CHANGE. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_state_change_type_set(EVENT_STATE_CHANGE * const state_change, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(state_change != NULL); + assert(state_change->header.event_domain == EVEL_DOMAIN_STATE_CHANGE); + evel_header_type_set(&state_change->header, type); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an additional field name/value pair to the State Change. + * + * The name and value are null delimited ASCII strings. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param state_change Pointer to the ::EVENT_STATE_CHANGE. + * @param name ASCIIZ string with the attribute's name. The caller + * does not need to preserve the value once the function + * returns. + * @param value ASCIIZ string with the attribute's value. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_state_change_addl_field_add(EVENT_STATE_CHANGE * const state_change, + const char * const name, + const char * const value) +{ + STATE_CHANGE_ADDL_FIELD * addl_field = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(state_change != NULL); + assert(state_change->header.event_domain == EVEL_DOMAIN_STATE_CHANGE); + assert(name != NULL); + assert(value != NULL); + + EVEL_DEBUG("Adding name=%s value=%s", name, value); + addl_field = malloc(sizeof(STATE_CHANGE_ADDL_FIELD)); + assert(addl_field != NULL); + memset(addl_field, 0, sizeof(STATE_CHANGE_ADDL_FIELD)); + addl_field->name = strdup(name); + addl_field->value = strdup(value); + assert(addl_field->name != NULL); + assert(addl_field->value != NULL); + + dlist_push_last(&state_change->additional_fields, addl_field); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the state change as a JSON state change. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param state_change Pointer to the ::EVENT_STATE_CHANGE to encode. + *****************************************************************************/ +void evel_json_encode_state_change(EVEL_JSON_BUFFER * jbuf, + EVENT_STATE_CHANGE * state_change) +{ + STATE_CHANGE_ADDL_FIELD * addl_field = NULL; + DLIST_ITEM * addl_field_item = NULL; + char * new_state; + char * old_state; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(state_change != NULL); + assert(state_change->header.event_domain == EVEL_DOMAIN_STATE_CHANGE); + + new_state = evel_entity_state(state_change->new_state); + old_state = evel_entity_state(state_change->old_state); + + evel_json_encode_header(jbuf, &state_change->header); + evel_json_open_named_object(jbuf, "stateChangeFields"); + + /***************************************************************************/ + /* Mandatory fields. */ + /***************************************************************************/ + evel_enc_kv_string(jbuf, "newState", new_state); + evel_enc_kv_string(jbuf, "oldState", old_state); + evel_enc_kv_string(jbuf, "stateInterface", state_change->state_interface); + + /***************************************************************************/ + /* Optional fields. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "additionalFields")) + { + bool item_added = false; + + addl_field_item = dlist_get_first(&state_change->additional_fields); + while (addl_field_item != NULL) + { + addl_field = (STATE_CHANGE_ADDL_FIELD *) addl_field_item->item; + assert(addl_field != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "additionalFields", + addl_field->name)) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "name", addl_field->name); + evel_enc_kv_string(jbuf, "value", addl_field->value); + evel_json_close_object(jbuf); + item_added = true; + } + addl_field_item = dlist_get_next(addl_field_item); + } + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + if (!item_added) + { + evel_json_rewind(jbuf); + } + } + + evel_enc_version(jbuf, + "stateChangeFieldsVersion", + state_change->major_version, + state_change->minor_version); + + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} diff --git a/vnfs/VES/code/evel_library/evel_strings.c b/vnfs/VES/code/evel_library/evel_strings.c new file mode 100644 index 00000000..1f410cb1 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_strings.c @@ -0,0 +1,477 @@ +/**************************************************************************//** + * @file + * Implementation of EVEL functions to convert common enum types to strings. + * + * License + * ------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include + +#include "evel_internal.h" + +/**************************************************************************//** + * Map an ::EVEL_COUNTER_CRITICALITIES enum value to the equivalent string. + * + * @param criticality The criticality to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_criticality(const EVEL_COUNTER_CRITICALITIES criticality) +{ + char * result; + + EVEL_ENTER(); + + switch (criticality) + { + case EVEL_COUNTER_CRITICALITY_CRIT: + result = "CRIT"; + break; + + case EVEL_COUNTER_CRITICALITY_MAJ: + result = "MAJ"; + break; + + default: + EVEL_ERROR("Unexpected counter criticality %d", criticality); + assert(0); + } + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Map an ::EVEL_SEVERITIES enum value to the equivalent string. + * + * @param severity The severity to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_severity(const EVEL_SEVERITIES severity) +{ + char * result; + + EVEL_ENTER(); + + switch (severity) + { + case EVEL_SEVERITY_CRITICAL: + result = "CRITICAL"; + break; + + case EVEL_SEVERITY_MAJOR: + result = "MAJOR"; + break; + + case EVEL_SEVERITY_MINOR: + result = "MINOR"; + break; + + case EVEL_SEVERITY_WARNING: + result = "WARNING"; + break; + + case EVEL_SEVERITY_NORMAL: + result = "NORMAL"; + break; + + default: + EVEL_ERROR("Unexpected event severity %d", severity); + assert(0); + } + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Map an ::EVEL_ALERT_ACTIONS enum value to the equivalent string. + * + * @param alert_action The alert_action to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_alert_action(const EVEL_ALERT_ACTIONS alert_action) +{ + char * result; + + EVEL_ENTER(); + + switch (alert_action) + { + case EVEL_ALERT_ACTION_CLEAR: + result = "CLEAR"; + break; + + case EVEL_ALERT_ACTION_CONT: + result = "CONT"; + break; + + case EVEL_ALERT_ACTION_SET: + result = "SET"; + break; + + default: + EVEL_ERROR("Unexpected alert action %d", alert_action); + assert(0); + } + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Map an ::EVEL_ALERT_TYPES enum value to the equivalent string. + * + * @param alert_type The alert_type to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_alert_type(const EVEL_ALERT_TYPES alert_type) +{ + char * result; + + EVEL_ENTER(); + + switch (alert_type) + { + case EVEL_ALERT_TYPE_CARD: + result = "CARD-ANOMALY"; + break; + + case EVEL_ALERT_TYPE_ELEMENT: + result = "ELEMENT-ANOMALY"; + break; + + case EVEL_ALERT_TYPE_INTERFACE: + result = "INTERFACE-ANOMALY"; + break; + + case EVEL_ALERT_TYPE_SERVICE: + result = "SERVICE-ANOMALY"; + break; + + default: + EVEL_ERROR("Unexpected alert type %d", alert_type); + assert(0); + } + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Map an ::EVEL_EVENT_DOMAINS enum value to the equivalent string. + * + * @param domain The domain to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_event_domain(const EVEL_EVENT_DOMAINS domain) +{ + char * result; + + EVEL_ENTER(); + + switch (domain) + { + case EVEL_DOMAIN_HEARTBEAT: + result = "heartbeat"; + break; + + case EVEL_DOMAIN_FAULT: + result = "fault"; + break; + + case EVEL_DOMAIN_MEASUREMENT: + result = "measurementsForVfScaling"; + break; + + case EVEL_DOMAIN_REPORT: + result = "measurementsForVfReporting"; + break; + + case EVEL_DOMAIN_MOBILE_FLOW: + result = "mobileFlow"; + break; + + case EVEL_DOMAIN_SERVICE: + result = "serviceEvents"; + break; + + case EVEL_DOMAIN_SIGNALING: + result = "signaling"; + break; + + case EVEL_DOMAIN_STATE_CHANGE: + result = "stateChange"; + break; + + case EVEL_DOMAIN_SYSLOG: + result = "syslog"; + break; + + case EVEL_DOMAIN_OTHER: + result = "other"; + break; + + default: + result = NULL; + EVEL_ERROR("Unexpected domain %d", domain); + assert(0); + } + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Map an ::EVEL_EVENT_PRIORITIES enum value to the equivalent string. + * + * @param priority The priority to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_event_priority(const EVEL_EVENT_PRIORITIES priority) +{ + char * result; + + EVEL_ENTER(); + + switch (priority) + { + case EVEL_PRIORITY_HIGH: + result = "High"; + break; + + case EVEL_PRIORITY_MEDIUM: + result = "Medium"; + break; + + case EVEL_PRIORITY_NORMAL: + result = "Normal"; + break; + + case EVEL_PRIORITY_LOW: + result = "Low"; + break; + + default: + result = NULL; + EVEL_ERROR("Unexpected priority %d", priority); + assert(0); + } + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Map an ::EVEL_SOURCE_TYPES enum value to the equivalent string. + * + * @param source_type The source type to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_source_type(const EVEL_SOURCE_TYPES source_type) +{ + char * result; + + EVEL_ENTER(); + + switch (source_type) + { + case EVEL_SOURCE_OTHER: + result = "other"; + break; + + case EVEL_SOURCE_ROUTER: + result = "router"; + break; + + case EVEL_SOURCE_SWITCH: + result = "switch"; + break; + + case EVEL_SOURCE_HOST: + result = "host"; + break; + + case EVEL_SOURCE_CARD: + result = "card"; + break; + + case EVEL_SOURCE_PORT: + result = "port"; + break; + + case EVEL_SOURCE_SLOT_THRESHOLD: + result = "slotThreshold"; + break; + + case EVEL_SOURCE_PORT_THRESHOLD: + result = "portThreshold"; + break; + + case EVEL_SOURCE_VIRTUAL_MACHINE: + result = "virtualMachine"; + break; + + case EVEL_SOURCE_VIRTUAL_NETWORK_FUNCTION: + result = "virtualNetworkFunction"; + break; + + default: + result = NULL; + EVEL_ERROR("Unexpected Event Source Type %d", (int) source_type); + assert(0); + } + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Map an ::EVEL_VF_STATUSES enum value to the equivalent string. + * + * @param vf_status The vf_status to convert. + * @returns The equivalent string. + *****************************************************************************/ +char * evel_vf_status(const EVEL_VF_STATUSES vf_status) +{ + char * result; + + EVEL_ENTER(); + + switch (vf_status) + { + case EVEL_VF_STATUS_ACTIVE: + result = "Active"; + break; + + case EVEL_VF_STATUS_IDLE: + result = "Idle"; + break; + + case EVEL_VF_STATUS_PREP_TERMINATE: + result = "Preparing to terminate"; + break; + + case EVEL_VF_STATUS_READY_TERMINATE: + result = "Ready to terminate"; + break; + + case EVEL_VF_STATUS_REQ_TERMINATE: + result = "Requesting termination"; + break; + + default: + result = NULL; + EVEL_ERROR("Unexpected VF Status %d", vf_status); + assert(0); + } + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Convert a ::EVEL_ENTITY_STATE to it's string form for JSON encoding. + * + * @param state The entity state to encode. + * + * @returns the corresponding string + *****************************************************************************/ +char * evel_entity_state(const EVEL_ENTITY_STATE state) +{ + char * result; + + EVEL_ENTER(); + + switch (state) + { + case EVEL_ENTITY_STATE_IN_SERVICE: + result = "inService"; + break; + + case EVEL_ENTITY_STATE_MAINTENANCE: + result = "maintenance"; + break; + + case EVEL_ENTITY_STATE_OUT_OF_SERVICE: + result = "outOfService"; + break; + + default: + EVEL_ERROR("Unexpected entity state %d", state); + assert(0); + } + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Convert a ::EVEL_SERVICE_ENDPOINT_DESC to string form for JSON encoding. + * + * @param endpoint_desc endpoint description to encode. + * + * @returns the corresponding string + *****************************************************************************/ +char * evel_service_endpoint_desc(const EVEL_ENTITY_STATE endpoint_desc) +{ + char * result; + + EVEL_ENTER(); + + switch (endpoint_desc) + { + case EVEL_SERVICE_ENDPOINT_CALLEE: + result = "Callee"; + break; + + case EVEL_SERVICE_ENDPOINT_CALLER: + result = "Caller"; + break; + + default: + EVEL_ERROR("Unexpected endpoint description %d", endpoint_desc); + assert(0); + } + + EVEL_EXIT(); + + return result; +} diff --git a/vnfs/VES/code/evel_library/evel_syslog.c b/vnfs/VES/code/evel_library/evel_syslog.c new file mode 100644 index 00000000..64a94886 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_syslog.c @@ -0,0 +1,500 @@ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the Syslog. + * + * License + * ------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include + +#include "evel_throttle.h" + +/**************************************************************************//** + * Create a new Syslog event. + * + * @note The mandatory fields on the Syslog must be supplied to this factory + * function and are immutable once set. Optional fields have explicit + * setter functions, but again values may only be set once so that the + * Syslog has immutable properties. + * @param event_source_type The type of Syslog event source. + * @param syslog_msg The Syslog event message. + * @param syslog_tag The messgaeId identifying the type of message. + * @returns pointer to the newly manufactured ::EVENT_SYSLOG. If the event is + * not used (i.e. posted) it must be released using + * ::evel_free_syslog. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_SYSLOG * evel_new_syslog(EVEL_SOURCE_TYPES event_source_type, + const char * const syslog_msg, + const char * const syslog_tag) +{ + EVENT_SYSLOG * syslog = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event_source_type < EVEL_MAX_SOURCE_TYPES); + assert(syslog_msg != NULL); + assert(syslog_tag != NULL); + + /***************************************************************************/ + /* Allocate the Syslog. */ + /***************************************************************************/ + syslog = malloc(sizeof(EVENT_SYSLOG)); + if (syslog == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(syslog, 0, sizeof(EVENT_SYSLOG)); + EVEL_DEBUG("New Syslog is at %lp", syslog); + + /***************************************************************************/ + /* Initialize the header & the Syslog fields. Optional string values are */ + /* uninitialized (NULL). */ + /***************************************************************************/ + evel_init_header(&syslog->header); + syslog->header.event_domain = EVEL_DOMAIN_SYSLOG; + syslog->major_version = EVEL_SYSLOG_MAJOR_VERSION; + syslog->minor_version = EVEL_SYSLOG_MINOR_VERSION; + syslog->event_source_type = event_source_type; + syslog->syslog_msg = strdup(syslog_msg); + syslog->syslog_tag = strdup(syslog_tag); + dlist_initialize(&syslog->additional_fields); + evel_init_option_int(&syslog->syslog_facility); + evel_init_option_int(&syslog->syslog_proc_id); + evel_init_option_int(&syslog->syslog_ver); + evel_init_option_string(&syslog->event_source_host); + evel_init_option_string(&syslog->syslog_proc); + evel_init_option_string(&syslog->syslog_s_data); + +exit_label: + EVEL_EXIT(); + return syslog; +} + +/**************************************************************************//** + * Set the Event Type property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the syslog. + * @param type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_type_set(EVENT_SYSLOG * syslog, + const char * const type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(syslog != NULL); + assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG); + evel_header_type_set(&syslog->header, type); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an additional value name/value pair to the Syslog. + * + * The name and value are null delimited ASCII strings. The library takes + * a copy so the caller does not have to preserve values after the function + * returns. + * + * @param syslog Pointer to the syslog. + * @param name ASCIIZ string with the attribute's name. The caller + * does not need to preserve the value once the function + * returns. + * @param value ASCIIZ string with the attribute's value. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_addl_field_add(EVENT_SYSLOG * syslog, + char * name, + char * value) +{ + SYSLOG_ADDL_FIELD * addl_field = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(syslog != NULL); + assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG); + assert(name != NULL); + assert(value != NULL); + + EVEL_DEBUG("Adding name=%s value=%s", name, value); + addl_field = malloc(sizeof(SYSLOG_ADDL_FIELD)); + assert(addl_field != NULL); + memset(addl_field, 0, sizeof(SYSLOG_ADDL_FIELD)); + addl_field->name = strdup(name); + addl_field->value = strdup(value); + assert(addl_field->name != NULL); + assert(addl_field->value != NULL); + + dlist_push_last(&syslog->additional_fields, addl_field); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Event Source Host property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the Syslog. + * @param host The Event Source Host to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_event_source_host_set(EVENT_SYSLOG * syslog, + const char * const host) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(syslog != NULL); + assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG); + assert(host != NULL); + + evel_set_option_string(&syslog->event_source_host, + host, + "Event Source Host"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Facility property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the Syslog. + * @param facility The Syslog Facility to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_facility_set(EVENT_SYSLOG * syslog, + EVEL_SYSLOG_FACILITIES facility) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(syslog != NULL); + assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG); + assert(facility < EVEL_MAX_SYSLOG_FACILITIES); + + evel_set_option_int(&syslog->syslog_facility, + facility, + "Facility"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Process property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the Syslog. + * @param proc The Process to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_syslog_proc_set(EVENT_SYSLOG * syslog, const char * const proc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(syslog != NULL); + assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG); + assert(proc != NULL); + + evel_set_option_string(&syslog->syslog_proc, proc, "Process"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Process ID property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the Syslog. + * @param proc_id The Process ID to be set. ASCIIZ string. The caller does + * not need to preserve the value once the function returns. + *****************************************************************************/ +void evel_syslog_proc_id_set(EVENT_SYSLOG * syslog, int proc_id) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(syslog != NULL); + assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG); + assert(proc_id > 0); + + evel_set_option_int(&syslog->syslog_proc_id, + proc_id, + "Process ID"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Version property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the Syslog. + * @param version The Version to be set. ASCIIZ string. The caller does not + * need to preserve the value once the function returns. + *****************************************************************************/ +void evel_syslog_version_set(EVENT_SYSLOG * syslog, int version) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(syslog != NULL); + assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG); + assert(version >= 0); + + evel_set_option_int(&syslog->syslog_ver, + version, + "Version"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Structured Data property of the Syslog. + * + * @note The property is treated as immutable: it is only valid to call + * the setter once. However, we don't assert if the caller tries to + * overwrite, just ignoring the update instead. + * + * @param syslog Pointer to the Syslog. + * @param s_data The Structured Data to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_s_data_set(EVENT_SYSLOG * syslog, const char * const s_data) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(syslog != NULL); + assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG); + assert(s_data != NULL); + + evel_set_option_string(&syslog->syslog_s_data, + s_data, + "Structured Data"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the Syslog in JSON according to AT&T's schema for the event type. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to encode into. + * @param event Pointer to the ::EVENT_HEADER to encode. + *****************************************************************************/ +void evel_json_encode_syslog(EVEL_JSON_BUFFER * jbuf, + EVENT_SYSLOG * event) +{ + char * event_source_type; + SYSLOG_ADDL_FIELD * addl_field = NULL; + DLIST_ITEM * addl_field_item = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SYSLOG); + + event_source_type = evel_source_type(event->event_source_type); + + evel_json_encode_header(jbuf, &event->header); + evel_json_open_named_object(jbuf, "syslogFields"); + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + evel_enc_kv_string(jbuf, "eventSourceType", event_source_type); + evel_enc_kv_string(jbuf, "syslogMsg", event->syslog_msg); + evel_enc_kv_string(jbuf, "syslogTag", event->syslog_tag); + evel_enc_version( + jbuf, "syslogFieldsVersion", event->major_version, event->minor_version); + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "additionalFields")) + { + bool item_added = false; + + addl_field_item = dlist_get_first(&event->additional_fields); + while (addl_field_item != NULL) + { + addl_field = (SYSLOG_ADDL_FIELD *) addl_field_item->item; + assert(addl_field != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "additionalFields", + addl_field->name)) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "name", addl_field->name); + evel_enc_kv_string(jbuf, "value", addl_field->value); + evel_json_close_object(jbuf); + item_added = true; + } + addl_field_item = dlist_get_next(addl_field_item); + } + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + if (!item_added) + { + evel_json_rewind(jbuf); + } + } + + evel_enc_kv_opt_string(jbuf, "eventSourceHost", &event->event_source_host); + evel_enc_kv_opt_int(jbuf, "syslogFacility", &event->syslog_facility); + evel_enc_kv_opt_string(jbuf, "syslogProc", &event->syslog_proc); + evel_enc_kv_opt_int(jbuf, "syslogProcId", &event->syslog_proc_id); + evel_enc_kv_opt_string(jbuf, "syslogSData", &event->syslog_s_data); + evel_enc_kv_opt_int(jbuf, "syslogVer", &event->syslog_ver); + evel_json_close_object(jbuf); + + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_KERNEL == 0); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_USER == 1); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_MAIL == 2); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_SYSTEM_DAEMON == 3); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_SECURITY_AUTH == 4); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_INTERNAL == 5); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LINE_PRINTER == 6); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_NETWORK_NEWS == 7); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_UUCP == 8); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_CLOCK_DAEMON == 9); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_SECURITY_AUTH2 == 10); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_FTP_DAEMON == 11); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_NTP == 12); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOG_AUDIT == 13); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOG_ALERT == 14); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_CLOCK_DAEMON2 == 15); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL0 == 16); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL1 == 17); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL2 == 18); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL3 == 19); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL4 == 20); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL5 == 21); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL6 == 22); + EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL7 == 23); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free a Syslog. + * + * Free off the Syslog supplied. Will free all the contained allocated memory. + * + * @note It does not free the Syslog itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_syslog(EVENT_SYSLOG * event) +{ + SYSLOG_ADDL_FIELD * addl_field = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the public API. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SYSLOG); + + /***************************************************************************/ + /* Free all internal strings then the header itself. */ + /***************************************************************************/ + addl_field = dlist_pop_last(&event->additional_fields); + while (addl_field != NULL) + { + EVEL_DEBUG("Freeing Additional Field (%s, %s)", + addl_field->name, + addl_field->value); + free(addl_field->name); + free(addl_field->value); + free(addl_field); + addl_field = dlist_pop_last(&event->additional_fields); + } + + evel_free_option_string(&event->event_source_host); + free(event->syslog_msg); + evel_free_option_string(&event->syslog_proc); + evel_free_option_string(&event->syslog_s_data); + free(event->syslog_tag); + evel_free_header(&event->header); + + EVEL_EXIT(); +} diff --git a/vnfs/VES/code/evel_library/evel_throttle.c b/vnfs/VES/code/evel_library/evel_throttle.c new file mode 100644 index 00000000..866ece01 --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_throttle.c @@ -0,0 +1,2114 @@ +/**************************************************************************//** + * @file + * Event Manager + * + * Simple event manager that is responsible for taking events (Heartbeats, + * Faults and Measurements) from the ring-buffer and posting them to the API. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*****************************************************************************/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "evel_throttle.h" + +/*****************************************************************************/ +/* The Event Throttling State for all domains, indexed by */ +/* ::EVEL_EVENT_DOMAINS, corresponding to JSON eventDomain. */ +/* */ +/* A given domain is in a throttled state if ::evel_throttle_spec is */ +/* non-NULL. */ +/*****************************************************************************/ +static EVEL_THROTTLE_SPEC * evel_throttle_spec[EVEL_MAX_DOMAINS]; + +/*****************************************************************************/ +/* The current measurement interval. Default: MEASUREMENT_INTERVAL_UKNOWN. */ +/* Must be protected by evel_measurement_interval_mutex. */ +/*****************************************************************************/ +static int evel_measurement_interval; + +/*****************************************************************************/ +/* Mutex protecting evel_measurement_interval from contention between an */ +/* EVEL client reading it, and the EVEL event handler updating it. */ +/*****************************************************************************/ +static pthread_mutex_t evel_measurement_interval_mutex; + +/*****************************************************************************/ +/* Flag stating that we have received a "provideThrottlingState" command. */ +/* Set during JSON processing and cleared on sending the throttling state. */ +/*****************************************************************************/ +static bool evel_provide_throttling_state; + +/*****************************************************************************/ +/* Holder for the "commandType" value during JSON processing. */ +/*****************************************************************************/ +static char * evel_command_type_value; + +/*****************************************************************************/ +/* Holder for the "measurementInterval" value during JSON processing. */ +/*****************************************************************************/ +static char * evel_measurement_interval_value; + +/*****************************************************************************/ +/* Holder for the "eventDomain" value during JSON processing. */ +/*****************************************************************************/ +static char * evel_throttle_spec_domain_value; + +/*****************************************************************************/ +/* Decoded version of ::evel_throttle_spec_domain_value. */ +/*****************************************************************************/ +static EVEL_EVENT_DOMAINS evel_throttle_spec_domain; + +/*****************************************************************************/ +/* During JSON processing of a single throttling specification, we collect */ +/* parameters in this working ::EVEL_THROTTLE_SPEC */ +/*****************************************************************************/ +static EVEL_THROTTLE_SPEC * evel_temp_throttle; + +/*****************************************************************************/ +/* State tracking our progress through the command list */ +/*****************************************************************************/ +EVEL_JSON_COMMAND_STATE evel_json_command_state; + +/*****************************************************************************/ +/* Debug strings for ::EVEL_JSON_COMMAND_STATE. */ +/*****************************************************************************/ +static const char * const evel_jcs_strings[EVEL_JCS_MAX] = { + "EVEL_JCS_START", + "EVEL_JCS_COMMAND_LIST", + "EVEL_JCS_COMMAND_LIST_ENTRY", + "EVEL_JCS_COMMAND", + "EVEL_JCS_SPEC", + "EVEL_JCS_FIELD_NAMES", + "EVEL_JCS_PAIRS_LIST", + "EVEL_JCS_PAIRS_LIST_ENTRY", + "EVEL_JCS_NV_PAIR_NAMES" +}; + +/*****************************************************************************/ +/* Debug strings for JSON token type. */ +/*****************************************************************************/ +#define JSON_TOKEN_TYPES (JSMN_PRIMITIVE + 1) +static const char * const evel_json_token_strings[JSON_TOKEN_TYPES] = { + "JSMN_UNDEFINED", + "JSMN_OBJECT", + "JSMN_ARRAY", + "JSMN_STRING", + "JSMN_PRIMITIVE" +}; + +/*****************************************************************************/ +/* Debug strings for JSON domains. */ +/*****************************************************************************/ +static const char * evel_domain_strings[EVEL_MAX_DOMAINS] = { + "internal", + "heartbeat", + "fault", + "measurementsForVfScaling", + "mobileFlow", + "report", + "serviceEvents", + "signaling", + "stateChange", + "syslog", + "other" +}; + +/*****************************************************************************/ +/* Local prototypes. */ +/*****************************************************************************/ +static void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec); +static struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys); +static void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec); +static void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs); +static void evel_init_json_stack(EVEL_JSON_STACK * json_stack, + const MEMORY_CHUNK * const chunk); +static bool evel_stack_push(EVEL_JSON_STACK * const json_stack, + const int num_required, + const EVEL_JSON_STATE new_state); +static void evel_stack_pop(EVEL_JSON_STACK * const json_stack); +static void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack); +static char * evel_stack_strdup(const MEMORY_CHUNK * const chunk, + const jsmntok_t * const token); +static void evel_stack_store_key(EVEL_JSON_STACK * const json_stack, + const jsmntok_t * const token); +static void evel_stack_store_value(EVEL_JSON_STACK * const json_stack, + const jsmntok_t * const token); +static void evel_stack_store_item(EVEL_JSON_STACK * const json_stack, + const jsmntok_t * const token); +static void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state); +static void evel_debug_token(const MEMORY_CHUNK * const chunk, + const jsmntok_t * const token); +static void evel_command_list_response(MEMORY_CHUNK * const post); +static int evel_json_encode_throttle(char * const json, const int max_size); +static int evel_json_encode_throttle_spec(char * const json, + const int max_size, + const EVEL_EVENT_DOMAINS domain); +static int evel_json_encode_nv_pairs(char * const json, + const int max_size, + EVEL_SUPPRESSED_NV_PAIRS * nv_pairs); +static void evel_close_command(); +static void evel_open_command(); +static void evel_set_throttling_spec(); +static void evel_set_measurement_interval(); +static void evel_open_throttle_spec(); +static void evel_close_throttle_spec(); +static EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value); +static void evel_open_nv_pairs_list_entry(); +static void evel_close_nv_pairs_list_entry(); +static void evel_store_nv_pair_field_name(char * const value); +static void evel_store_nv_pair_name(char * const item); +static void evel_store_suppressed_field_name(char * const item); +static EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs(); + +/**************************************************************************//** + * Return the current measurement interval provided by the Event Listener. + * + * @returns The current measurement interval + * @retval EVEL_MEASUREMENT_INTERVAL_UKNOWN (0) - interval has not been + * specified + *****************************************************************************/ +int evel_get_measurement_interval() +{ + int result; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Lock, read, unlock. */ + /***************************************************************************/ + pthread_mutex_lock(&evel_measurement_interval_mutex); + result = evel_measurement_interval; + pthread_mutex_unlock(&evel_measurement_interval_mutex); + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Return the ::EVEL_THROTTLE_SPEC for a given domain. + * + * @param domain The domain for which to return state. + *****************************************************************************/ +EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain) +{ + EVEL_THROTTLE_SPEC * result; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(domain < EVEL_MAX_DOMAINS); + + result = evel_throttle_spec[domain]; + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Determine whether a field_name should be suppressed. + * + * @param throttle_spec Throttle specification for the domain being encoded. + * @param field_name The field name to encoded or suppress. + * @return true if the field_name should be suppressed, false otherwise. + *****************************************************************************/ +bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC * throttle_spec, + const char * const field_name) +{ + bool suppress = false; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(field_name != NULL); + + /***************************************************************************/ + /* If the throttle spec and hash table exist, query the field_names table. */ + /***************************************************************************/ + if ((throttle_spec != NULL) && (throttle_spec->hash_field_names != NULL)) + { + ENTRY hash_query; + ENTRY * hash_result; + hash_query.key = (char * const) field_name; + suppress = (hsearch_r(hash_query, + FIND, + &hash_result, + throttle_spec->hash_field_names) != 0); + } + + EVEL_EXIT(); + + return suppress; +} + +/**************************************************************************//** + * Determine whether a name-value pair should be allowed (not suppressed). + * + * @param throttle_spec Throttle specification for the domain being encoded. + * @param field_name The field name holding the name-value pairs. + * @param name The name of the name-value pair to encoded or suppress. + * @return true if the name-value pair should be suppressed, false otherwise. + *****************************************************************************/ +bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC * throttle_spec, + const char * const field_name, + const char * const name) +{ + EVEL_SUPPRESSED_NV_PAIRS * nv_pairs; + bool hit = false; + bool suppress = false; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(field_name != NULL); + assert(name != NULL); + + /***************************************************************************/ + /* If the throttle spec and hash table exist, query the nv_pairs table. */ + /***************************************************************************/ + if ((throttle_spec != NULL) && (throttle_spec->hash_nv_pairs_list != NULL)) + { + ENTRY hash_query; + ENTRY * hash_result; + hash_query.key = (char * const) field_name; + hit = (hsearch_r(hash_query, + FIND, + &hash_result, + throttle_spec->hash_nv_pairs_list) != 0); + if (hit) + { + nv_pairs = hash_result->data; + } + } + + /***************************************************************************/ + /* If we got a hit, and the nv_pairs and hash table exist, query the */ + /* nv_pairs table. */ + /***************************************************************************/ + if (hit && (nv_pairs != NULL) && (nv_pairs->hash_nv_pair_names != NULL)) + { + ENTRY hash_query; + ENTRY * hash_result; + hash_query.key = (char * const) name; + suppress = (hsearch_r(hash_query, + FIND, + &hash_result, + nv_pairs->hash_nv_pair_names) != 0); + } + + EVEL_EXIT(); + + return suppress; +} + +/**************************************************************************//** + * Initialize event throttling to the default state. + * + * Called from ::evel_initialize. + *****************************************************************************/ +void evel_throttle_initialize() +{ + int pthread_rc; + int ii; + + EVEL_ENTER(); + + for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++) + { + evel_throttle_spec[ii] = NULL; + } + + pthread_rc = pthread_mutex_init(&evel_measurement_interval_mutex, NULL); + assert(pthread_rc == 0); + + evel_measurement_interval = EVEL_MEASUREMENT_INTERVAL_UKNOWN; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Clean up event throttling. + * + * Called from ::evel_terminate. + *****************************************************************************/ +void evel_throttle_terminate() +{ + int pthread_rc; + int ii; + + EVEL_ENTER(); + + for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++) + { + if (evel_throttle_spec[ii] != NULL) + { + evel_throttle_free(evel_throttle_spec[ii]); + evel_throttle_spec[ii] = NULL; + } + } + + pthread_rc = pthread_mutex_destroy(&evel_measurement_interval_mutex); + assert(pthread_rc == 0); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Finalize a single ::EVEL_THROTTLE_SPEC. + * + * Now that the specification is collected, build hash tables to simplify the + * throttling itself. + * + * @param throttle_spec The ::EVEL_THROTTLE_SPEC to finalize. + *****************************************************************************/ +void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec) +{ + int nv_pairs_count; + DLIST_ITEM * dlist_item; + ENTRY * add_result; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(throttle_spec != NULL); + + /***************************************************************************/ + /* Populate the hash table for suppressed field names. */ + /***************************************************************************/ + throttle_spec->hash_field_names = + evel_throttle_hash_create(&throttle_spec->suppressed_field_names); + + /***************************************************************************/ + /* Create the hash table for suppressed nv pairs. */ + /***************************************************************************/ + nv_pairs_count = dlist_count(&throttle_spec->suppressed_nv_pairs_list); + if (nv_pairs_count > 0) + { + throttle_spec->hash_nv_pairs_list = calloc(1, sizeof(struct hsearch_data)); + assert(throttle_spec->hash_nv_pairs_list != NULL); + + /*************************************************************************/ + /* Provide plenty of space in the table - see hcreate_r notes. */ + /*************************************************************************/ + if (hcreate_r(nv_pairs_count * 2, throttle_spec->hash_nv_pairs_list) == 0) + { + EVEL_ERROR("Failed to create hash table"); + free(throttle_spec->hash_nv_pairs_list); + throttle_spec->hash_nv_pairs_list = NULL; + } + } + + /***************************************************************************/ + /* Populate the hash tables under suppressed field names. */ + /***************************************************************************/ + dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list); + while (dlist_item != NULL) + { + EVEL_SUPPRESSED_NV_PAIRS * nv_pairs = dlist_item->item; + ENTRY hash_add; + + /*************************************************************************/ + /* Set the key to the string, and the item to the nv_pairs. */ + /*************************************************************************/ + assert(nv_pairs != NULL); + hash_add.key = nv_pairs->nv_pair_field_name; + hash_add.data = nv_pairs; + hsearch_r(hash_add, ENTER, &add_result, throttle_spec->hash_nv_pairs_list); + + /*************************************************************************/ + /* Create the nv_pair_names hash since we're in here. */ + /*************************************************************************/ + nv_pairs->hash_nv_pair_names = + evel_throttle_hash_create(&nv_pairs->suppressed_nv_pair_names); + + dlist_item = dlist_get_next(dlist_item); + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Create and populate a hash table from a DLIST of keys. + * + * @param hash_keys Pointer to a DLIST of hash table keys. + * @return Pointer to the created hash-table, or NULL on failure. + *****************************************************************************/ +struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys) +{ + int key_count; + struct hsearch_data * hash_table; + ENTRY * add_result; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(hash_keys != NULL); + + /***************************************************************************/ + /* Count the keys and if there are any, populate the hash table with them. */ + /***************************************************************************/ + key_count = dlist_count(hash_keys); + if (key_count > 0) + { + EVEL_DEBUG("Populating table for %d keys", key_count); + + hash_table = calloc(1, sizeof(struct hsearch_data)); + assert(hash_table != NULL); + + /*************************************************************************/ + /* We need to leave plenty of space in the table - see hcreate_r notes. */ + /*************************************************************************/ + if (hcreate_r(key_count * 2, hash_table) != 0) + { + DLIST_ITEM * dlist_item; + dlist_item = dlist_get_first(hash_keys); + while (dlist_item != NULL) + { + assert(dlist_item->item != NULL); + + /*********************************************************************/ + /* Set the key and data to the item, which is a string in this case. */ + /*********************************************************************/ + ENTRY hash_add; + hash_add.key = dlist_item->item; + hash_add.data = dlist_item->item; + hsearch_r(hash_add, ENTER, &add_result, hash_table); + dlist_item = dlist_get_next(dlist_item); + } + } + else + { + EVEL_ERROR("Failed to create hash table"); + free(hash_table); + hash_table = NULL; + } + } + else + { + hash_table = NULL; + } + + EVEL_EXIT(); + + return hash_table; +} + +/**************************************************************************//** + * Free resources associated with a single ::EVEL_THROTTLE_SPEC. + * + * @param throttle_spec The ::EVEL_THROTTLE_SPEC to free. + *****************************************************************************/ +void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec) +{ + char * field_name; + EVEL_SUPPRESSED_NV_PAIRS * nv_pairs; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(throttle_spec != NULL); + + /***************************************************************************/ + /* Free any hash tables. */ + /***************************************************************************/ + if (throttle_spec->hash_field_names != NULL) + { + hdestroy_r(throttle_spec->hash_field_names); + free(throttle_spec->hash_field_names); + } + if (throttle_spec->hash_nv_pairs_list != NULL) + { + hdestroy_r(throttle_spec->hash_nv_pairs_list); + free(throttle_spec->hash_nv_pairs_list); + } + + /***************************************************************************/ + /* Iterate through the linked lists, freeing memory. */ + /***************************************************************************/ + field_name = dlist_pop_last(&throttle_spec->suppressed_field_names); + while (field_name != NULL) + { + free(field_name); + field_name = dlist_pop_last(&throttle_spec->suppressed_field_names); + } + + nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list); + while (nv_pairs != NULL) + { + evel_throttle_free_nv_pair(nv_pairs); + nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list); + } + + free(throttle_spec); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free resources associated with a single ::EVEL_SUPPRESSED_NV_PAIR. + * + * @param nv_pair The ::EVEL_SUPPRESSED_NV_PAIR to free. + *****************************************************************************/ +void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs) +{ + char * suppressed_name; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(nv_pairs != NULL); + + /***************************************************************************/ + /* Free any hash tables. */ + /***************************************************************************/ + if (nv_pairs->hash_nv_pair_names != NULL) + { + hdestroy_r(nv_pairs->hash_nv_pair_names); + free(nv_pairs->hash_nv_pair_names); + } + + /***************************************************************************/ + /* Iterate through the linked lists, freeing memory. */ + /***************************************************************************/ + suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names); + while (suppressed_name != NULL) + { + free(suppressed_name); + suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names); + } + if (nv_pairs->nv_pair_field_name != NULL) + { + free(nv_pairs->nv_pair_field_name); + } + free(nv_pairs); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Handle a JSON response from the listener, as a list of tokens from JSMN. + * + * @param chunk Memory chunk containing the JSON buffer. + * @param json_tokens Array of tokens to handle. + * @param num_tokens The number of tokens to handle. + * @param post The memory chunk in which to place any resulting POST. + * @return true if the command was handled, false otherwise. + *****************************************************************************/ +bool evel_handle_command_list(const MEMORY_CHUNK * const chunk, + const jsmntok_t * const json_tokens, + const int num_tokens, + MEMORY_CHUNK * const post) +{ + EVEL_JSON_STACK stack; + EVEL_JSON_STACK * json_stack = &stack; + EVEL_JSON_STACK_ENTRY * entry; + + bool json_ok = true; + int token_index = 0; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(chunk != NULL); + assert(json_tokens != NULL); + assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS); + + /***************************************************************************/ + /* Collect one top-level item. */ + /***************************************************************************/ + evel_init_json_stack(json_stack, chunk); + + /***************************************************************************/ + /* Initialize JSON processing variables. */ + /***************************************************************************/ + evel_provide_throttling_state = false; + evel_command_type_value = NULL; + evel_measurement_interval_value = NULL; + evel_throttle_spec_domain_value = NULL; + evel_throttle_spec_domain = EVEL_MAX_DOMAINS; + evel_temp_throttle = NULL; + evel_json_command_state = EVEL_JCS_START; + + /***************************************************************************/ + /* Loop through the tokens, keeping a stack of state representing the */ + /* nested JSON structure (see json_state). We also track our way through */ + /* the ::EVEL_JSON_COMMAND_STATE as we go. */ + /***************************************************************************/ + while (json_ok && (token_index < num_tokens)) + { + const jsmntok_t * const token = &json_tokens[token_index]; + + if (EVEL_DEBUG_ON()) + { + evel_debug_token(chunk, token); + } + + /*************************************************************************/ + /* We may have popped or pushed, so always re-evaluate the stack entry. */ + /*************************************************************************/ + entry = &json_stack->entry[json_stack->level]; + + switch(token->type) + { + case JSMN_OBJECT: + if ((entry->json_state == EVEL_JSON_ITEM) || + (entry->json_state == EVEL_JSON_VALUE)) + { + json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_KEY); + } + else + { + EVEL_ERROR("Unexpected JSON state %d at token %d (%d)", + entry->json_state, token_index, token->type); + json_ok = false; + } + break; + + case JSMN_ARRAY: + if ((entry->json_state == EVEL_JSON_ITEM) || + (entry->json_state == EVEL_JSON_VALUE)) + { + json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_ITEM); + } + else + { + EVEL_ERROR("Unexpected JSON state %d at token %d (%d)", + entry->json_state, token_index, token->type); + json_ok = false; + } + break; + + case JSMN_STRING: + if (entry->json_state == EVEL_JSON_KEY) + { + evel_stack_store_key(json_stack, token); + } + else if (entry->json_state == EVEL_JSON_VALUE) + { + evel_stack_store_value(json_stack, token); + } + else if (entry->json_state == EVEL_JSON_ITEM) + { + evel_stack_store_item(json_stack, token); + } + else + { + EVEL_ERROR("Unexpected JSON state %d at token %d (%d)", + entry->json_state, token_index, token->type); + json_ok = false; + } + break; + + case JSMN_PRIMITIVE: + if (entry->json_state == EVEL_JSON_VALUE) + { + evel_stack_store_value(json_stack, token); + } + else if (entry->json_state == EVEL_JSON_ITEM) + { + evel_stack_store_item(json_stack, token); + } + else + { + EVEL_ERROR("Unexpected JSON state %d at token %d (%d)", + entry->json_state, token_index, token->type); + json_ok = false; + } + break; + + case JSMN_UNDEFINED: + default: + EVEL_ERROR("Unexpected JSON format at token %d (%d)", + token_index, token->type); + json_ok = false; + break; + } + + /*************************************************************************/ + /* Pop the stack if we're counted enough nested items. */ + /*************************************************************************/ + evel_stack_pop(json_stack); + + token_index++; + } + + /***************************************************************************/ + /* Cleanup the stack - we may have exited without winding it back, if the */ + /* input was not well formed. */ + /***************************************************************************/ + evel_stack_cleanup(json_stack); + + /***************************************************************************/ + /* We may want to generate and POST a response to the command list. */ + /***************************************************************************/ + if (json_ok) + { + evel_command_list_response(post); + } + + /***************************************************************************/ + /* Make sure we're clean on exit. */ + /***************************************************************************/ + assert(evel_command_type_value == NULL); + assert(evel_measurement_interval_value == NULL); + assert(evel_throttle_spec_domain_value == NULL); + assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS); + assert(evel_temp_throttle == NULL); + + EVEL_EXIT(); + + return json_ok; +} + +/**************************************************************************//** + * Copy a copy of an element, in string form. + * + * The caller must manage memory allocated for the copied string. + * + * @param chunk Memory chunk containing the JSON buffer. + * @param token The token to copy from. + * @return the copy of the element. + *****************************************************************************/ +char * evel_stack_strdup(const MEMORY_CHUNK * const chunk, + const jsmntok_t * const token) +{ + char temp_char; + char * result; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Call strdup to copy the string, inserting a temporary \0 for the call. */ + /***************************************************************************/ + temp_char = chunk->memory[token->end]; + chunk->memory[token->end] = '\0'; + result = strdup(chunk->memory + token->start); + assert(result != NULL); + chunk->memory[token->end] = temp_char; + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Copy a copy of an element, in string form. + * + * @param json_stack The JSON stack to initialize. + * @param chunk The underlying memory chunk used for parsing. + *****************************************************************************/ +void evel_init_json_stack(EVEL_JSON_STACK * json_stack, + const MEMORY_CHUNK * const chunk) +{ + EVEL_JSON_STACK_ENTRY * entry; + + EVEL_ENTER(); + + json_stack->level = 0; + entry = json_stack->entry; + entry->json_state = EVEL_JSON_ITEM; + entry->json_count = 0; + entry->num_required = 1; + entry->json_key = NULL; + json_stack->chunk = chunk; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Push a new entry on the stack + * + * @param json_stack The stack. + * @param num_required The number of elements required. + * @param new_state The state for the new entry. + * @return false if we cannot push onto the stack. + *****************************************************************************/ +bool evel_stack_push(EVEL_JSON_STACK * const json_stack, + const int num_required, + const EVEL_JSON_STATE new_state) +{ + EVEL_JSON_STACK_ENTRY * entry; + char * key; + bool result; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(json_stack != NULL); + assert(json_stack->level >= 0); + assert(json_stack->level < EVEL_JSON_STACK_DEPTH); + assert((new_state == EVEL_JSON_ITEM) || (new_state == EVEL_JSON_KEY)); + + /***************************************************************************/ + /* Check nesting depth, and stop processing if we hit the limit. */ + /***************************************************************************/ + if ((json_stack->level + 1) >= EVEL_JSON_STACK_DEPTH) + { + EVEL_ERROR("JSON Nesting is too deep - stop processing"); + result = false; + goto exit_label; + } + + /***************************************************************************/ + /* Evaluate cases where we recurse and are interested in the contents. */ + /***************************************************************************/ + entry = &json_stack->entry[json_stack->level]; + key = entry->json_key; + + /***************************************************************************/ + /* Note that this is the key before we drop a level. */ + /***************************************************************************/ + if (key != NULL) + { + EVEL_DEBUG("Push with key: %s", key); + + switch (evel_json_command_state) + { + case EVEL_JCS_START: + if (strcmp(key, "commandList") == 0) + { + evel_set_command_state(EVEL_JCS_COMMAND_LIST); + } + break; + + case EVEL_JCS_COMMAND_LIST_ENTRY: + if (strcmp(key, "command") == 0) + { + evel_open_command(); + evel_set_command_state(EVEL_JCS_COMMAND); + } + break; + + case EVEL_JCS_COMMAND: + if (strcmp(key, "eventDomainThrottleSpecification") == 0) + { + evel_open_throttle_spec(); + evel_set_command_state(EVEL_JCS_SPEC); + } + break; + + case EVEL_JCS_SPEC: + if (strcmp(key, "suppressedFieldNames") == 0) + { + evel_set_command_state(EVEL_JCS_FIELD_NAMES); + } + else if (strcmp(key, "suppressedNvPairsList") == 0) + { + evel_set_command_state(EVEL_JCS_PAIRS_LIST); + } + break; + + case EVEL_JCS_PAIRS_LIST_ENTRY: + if (strcmp(key, "suppressedNvPairNames") == 0) + { + evel_set_command_state(EVEL_JCS_NV_PAIR_NAMES); + } + break; + + case EVEL_JCS_FIELD_NAMES: + case EVEL_JCS_PAIRS_LIST: + case EVEL_JCS_NV_PAIR_NAMES: + default: + EVEL_ERROR("Unexpected JSON key %s in state %d", + key, + evel_json_command_state); + break; + } + } + else + { + EVEL_DEBUG("Push with no key"); + + /*************************************************************************/ + /* If we're pushing without a key, then we're in an array. We switch */ + /* state based on the existing state and stack level. */ + /*************************************************************************/ + const int COMMAND_LIST_LEVEL = 2; + const int NV_PAIRS_LIST_LEVEL = 6; + + if ((evel_json_command_state == EVEL_JCS_PAIRS_LIST) && + (json_stack->level == NV_PAIRS_LIST_LEVEL)) + { + /***********************************************************************/ + /* We are entering an object within the "suppressedNvPairsList" array. */ + /***********************************************************************/ + evel_open_nv_pairs_list_entry(); + evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY); + } + + if ((evel_json_command_state == EVEL_JCS_COMMAND_LIST) && + (json_stack->level == COMMAND_LIST_LEVEL)) + { + /***********************************************************************/ + /* We are entering an object within the "commandList" array. */ + /***********************************************************************/ + evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY); + } + } + + /***************************************************************************/ + /* Push the stack and initialize the entry. */ + /***************************************************************************/ + json_stack->level++; + entry++; + EVEL_DEBUG("Stack Push -> %d", json_stack->level); + entry = &json_stack->entry[json_stack->level]; + entry->json_count = 0; + entry->num_required = num_required; + entry->json_state = new_state; + entry->json_key = NULL; + result = true; + +exit_label: + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Pop any stack entries which have collected the required number of items. + * + * @param json_stack The stack. + *****************************************************************************/ +void evel_stack_pop(EVEL_JSON_STACK * const json_stack) +{ + EVEL_JSON_STACK_ENTRY * entry; + char * key; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(json_stack != NULL); + assert(json_stack->level >= 0); + assert(json_stack->level < EVEL_JSON_STACK_DEPTH); + + entry = &json_stack->entry[json_stack->level]; + while ((json_stack->level > 0) && (entry->json_count == entry->num_required)) + { + key = entry->json_key; + + switch (evel_json_command_state) + { + case EVEL_JCS_COMMAND_LIST: + evel_set_command_state(EVEL_JCS_START); + break; + + case EVEL_JCS_COMMAND_LIST_ENTRY: + evel_set_command_state(EVEL_JCS_COMMAND_LIST); + break; + + case EVEL_JCS_COMMAND: + evel_close_command(); + evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY); + break; + + case EVEL_JCS_SPEC: + evel_close_throttle_spec(); + evel_set_command_state(EVEL_JCS_COMMAND); + break; + + case EVEL_JCS_FIELD_NAMES: + evel_set_command_state(EVEL_JCS_SPEC); + break; + + case EVEL_JCS_PAIRS_LIST: + evel_set_command_state(EVEL_JCS_SPEC); + break; + + case EVEL_JCS_PAIRS_LIST_ENTRY: + evel_close_nv_pairs_list_entry(); + evel_set_command_state(EVEL_JCS_PAIRS_LIST); + break; + + case EVEL_JCS_NV_PAIR_NAMES: + evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY); + break; + + default: + break; + } + + /*************************************************************************/ + /* Free off any key that was duplicated and stored. */ + /*************************************************************************/ + if (key != NULL) + { + free(key); + entry->json_key = NULL; + } + + /*************************************************************************/ + /* We just reached the required number of key-value pairs or items, so */ + /* pop the stack. */ + /*************************************************************************/ + json_stack->level--; + entry--; + + EVEL_DEBUG("Stack Pop -> %d", json_stack->level); + + /*************************************************************************/ + /* We just completed collection of an ITEM (within an ARRAY) or a VALUE */ + /* (within an OBJECT). Either way, we need to count it. */ + /*************************************************************************/ + entry->json_count++; + + /*************************************************************************/ + /* If we just completed a VALUE, then we expect the next element to be a */ + /* key, if there is a next element. */ + /*************************************************************************/ + if (entry->json_state == EVEL_JSON_VALUE) + { + entry->json_state = EVEL_JSON_KEY; + } + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Pop all stack entries, freeing any memory as we go. + * + * @param json_stack The stack. + *****************************************************************************/ +void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack) +{ + EVEL_JSON_STACK_ENTRY * entry; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(json_stack != NULL); + assert(json_stack->level >= 0); + assert(json_stack->level < EVEL_JSON_STACK_DEPTH); + + entry = &json_stack->entry[json_stack->level]; + while ((json_stack->level > 0)) + { + /*************************************************************************/ + /* Free off any key that was duplicated and stored. */ + /*************************************************************************/ + if (entry->json_key != NULL) + { + free(entry->json_key); + entry->json_key = NULL; + } + + /*************************************************************************/ + /* We just reached the required number of key-value pairs or items, so */ + /* pop the stack. */ + /*************************************************************************/ + json_stack->level--; + entry--; + } + + /***************************************************************************/ + /* If we hit EVEL_JSON_STACK_DEPTH, we exit the loop and can leave these */ + /* values hanging - so clean them up. */ + /***************************************************************************/ + if (evel_command_type_value != NULL) + { + free(evel_command_type_value); + evel_command_type_value = NULL; + } + if (evel_measurement_interval_value != NULL) + { + free(evel_measurement_interval_value); + evel_measurement_interval_value = NULL; + } + if (evel_throttle_spec_domain_value != NULL) + { + free(evel_throttle_spec_domain_value); + evel_throttle_spec_domain_value = NULL; + } + evel_throttle_spec_domain = EVEL_MAX_DOMAINS; + if (evel_temp_throttle != NULL) + { + evel_throttle_free(evel_temp_throttle); + evel_temp_throttle = NULL; + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Store a key in the JSON stack. + * + * We always store the most recent key at each level in the stack. + * + * @param json_stack The stack. + * @param token The token holding the key. + *****************************************************************************/ +void evel_stack_store_key(EVEL_JSON_STACK * const json_stack, + const jsmntok_t * const token) +{ + EVEL_JSON_STACK_ENTRY * entry; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(json_stack != NULL); + assert(json_stack->level >= 0); + assert(json_stack->level < EVEL_JSON_STACK_DEPTH); + + /***************************************************************************/ + /* Free any previously stored key, replacing it with the new one. */ + /***************************************************************************/ + entry = &json_stack->entry[json_stack->level]; + if (entry->json_key != NULL) + { + free(entry->json_key); + } + entry->json_key = evel_stack_strdup(json_stack->chunk, token); + + /***************************************************************************/ + /* Switch state to collecting the corresponding value. */ + /***************************************************************************/ + entry->json_state = EVEL_JSON_VALUE; + + EVEL_DEBUG("Stored key: %s", entry->json_key); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Store a value in the JSON stack. + * + * @param json_stack The stack. + * @param token The token holding the value. + *****************************************************************************/ +void evel_stack_store_value(EVEL_JSON_STACK * const json_stack, + const jsmntok_t * const token) +{ + EVEL_JSON_STACK_ENTRY * entry; + char * value; + bool stored; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(json_stack != NULL); + assert(json_stack->level >= 0); + assert(json_stack->level < EVEL_JSON_STACK_DEPTH); + + /***************************************************************************/ + /* Based on the (key, state), work out whether we're expecting a value, */ + /* then store or ignore it as required. */ + /***************************************************************************/ + entry = &json_stack->entry[json_stack->level]; + value = evel_stack_strdup(json_stack->chunk, token); + stored = false; + EVEL_DEBUG("Store value: %s", value); + + switch (evel_json_command_state) + { + case EVEL_JCS_COMMAND: + if (strcmp(entry->json_key, "commandType") == 0) + { + evel_command_type_value = value; + stored = true; + } + else if (strcmp(entry->json_key, "measurementInterval") == 0) + { + evel_measurement_interval_value = value; + stored = true; + } + break; + + case EVEL_JCS_SPEC: + if (strcmp(entry->json_key, "eventDomain") == 0) + { + evel_throttle_spec_domain_value = value; + stored = true; + } + break; + + case EVEL_JCS_PAIRS_LIST_ENTRY: + if (strcmp(entry->json_key, "nvPairFieldName") == 0) + { + evel_store_nv_pair_field_name(value); + stored = true; + } + break; + + default: + EVEL_DEBUG("Ignoring value in state: %s", + evel_jcs_strings[evel_json_command_state]); + break; + } + + if (!stored) + { + EVEL_DEBUG("Ignored value: %s", value); + free(value); + } + + /***************************************************************************/ + /* Switch state to another key. */ + /***************************************************************************/ + entry->json_state = EVEL_JSON_KEY; + + /***************************************************************************/ + /* Count the key-value pair. */ + /***************************************************************************/ + entry->json_count++; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Store an item in the JSON stack - a string or primitive in an array. + * + * @param json_stack The stack. + * @param token The token holding the item. + *****************************************************************************/ +void evel_stack_store_item(EVEL_JSON_STACK * const json_stack, + const jsmntok_t * const token) +{ + EVEL_JSON_STACK_ENTRY * entry; + char * item; + bool stored; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(json_stack != NULL); + assert(json_stack->level >= 0); + assert(json_stack->level < EVEL_JSON_STACK_DEPTH); + + /***************************************************************************/ + /* Based on the state, work out whether we're expecting an item, then */ + /* store or ignore it as required. */ + /***************************************************************************/ + entry = &json_stack->entry[json_stack->level]; + item = evel_stack_strdup(json_stack->chunk, token); + stored = false; + EVEL_DEBUG("Store item: %s", item); + + switch (evel_json_command_state) + { + case EVEL_JCS_NV_PAIR_NAMES: + evel_store_nv_pair_name(item); + stored = true; + break; + + case EVEL_JCS_FIELD_NAMES: + evel_store_suppressed_field_name(item); + stored = true; + break; + + default: + EVEL_DEBUG("Ignoring item in state: %s", + evel_jcs_strings[evel_json_command_state]); + break; + } + + if (!stored) + { + EVEL_DEBUG("Ignored item: %s", item); + free(item); + } + + /***************************************************************************/ + /* We need another item. This is purely defensive. */ + /***************************************************************************/ + entry->json_state = EVEL_JSON_ITEM; + + /***************************************************************************/ + /* Count the item. */ + /***************************************************************************/ + entry->json_count++; +} + +/**************************************************************************//** + * Set the JSON command state to a new value. + * + * @param new_state The new state to set. + *****************************************************************************/ +void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(evel_json_command_state < EVEL_JCS_MAX); + assert(new_state < EVEL_JCS_MAX); + + /***************************************************************************/ + /* Provide common debug, and set the new state. */ + /***************************************************************************/ + EVEL_DEBUG("Command State: %s -> %s", + evel_jcs_strings[evel_json_command_state], + evel_jcs_strings[new_state]); + evel_json_command_state = new_state; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Produce debug output from a JSON token. + * + * @param chunk Memory chunk containing the JSON buffer. + * @param token Token to dump. + *****************************************************************************/ +void evel_debug_token(const MEMORY_CHUNK * const chunk, + const jsmntok_t * const token) +{ + char temp_char; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(token->type > 0); + assert(token->type < JSON_TOKEN_TYPES); + + /***************************************************************************/ + /* Log the token, leaving it in the state in which it started. */ + /***************************************************************************/ + temp_char = chunk->memory[token->end]; + chunk->memory[token->end] = '\0'; + EVEL_DEBUG("JSON token type: %s", evel_json_token_strings[token->type]); + EVEL_DEBUG("JSON token: %s", chunk->memory + token->start); + chunk->memory[token->end] = temp_char; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Post a response to the commandList. + * + * @param post Memory chunk in which to post a response. + *****************************************************************************/ +void evel_command_list_response(MEMORY_CHUNK * const post) +{ + char * json_post; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(post != NULL); + assert(post->memory == NULL); + + if (evel_provide_throttling_state) + { + EVEL_DEBUG("Provide throttling state"); + + /*************************************************************************/ + /* Encode the response, making it printf-able for debug. */ + /*************************************************************************/ + json_post = malloc(EVEL_MAX_JSON_BODY); + assert(json_post != NULL); + post->size = evel_json_encode_throttle(json_post, EVEL_MAX_JSON_BODY - 1); + post->memory = json_post; + post->memory[post->size] = '\0'; + evel_provide_throttling_state = false; + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the full throttling specification according to AT&T's schema. + * + * @param json Pointer to where to store the JSON encoded data. + * @param max_size Size of storage available in json_body. + * @returns Number of bytes actually written. + *****************************************************************************/ +int evel_json_encode_throttle(char * const json, const int max_size) +{ + bool throttled; + int domain; + int offset; + bool domain_added; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(json != NULL); + assert(max_size > 0); + + /***************************************************************************/ + /* Work out if we're throttled. */ + /***************************************************************************/ + throttled = false; + for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++) + { + if (evel_throttle_spec[domain] != NULL) + { + throttled = true; + } + } + + /***************************************************************************/ + /* Encode the response. */ + /***************************************************************************/ + offset = 0; + offset += snprintf(json + offset, max_size - offset, + "{\"eventThrottlingState\": {"); + offset += snprintf(json + offset, max_size - offset, + "\"eventThrottlingMode\": \"%s\"", + throttled ? "throttled" : "normal"); + if (throttled) + { + offset += snprintf(json + offset, max_size - offset, + ", \"eventDomainThrottleSpecificationList\": ["); + + domain_added = false; + for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++) + { + if (evel_throttle_spec[domain] != NULL) + { + if (domain_added) + { + offset += snprintf(json + offset, max_size - offset, ", "); + } + + offset += evel_json_encode_throttle_spec(json + offset, + max_size - offset, + domain); + domain_added = true; + } + } + + offset += snprintf(json + offset, max_size - offset, "]"); + } + + offset += snprintf(json + offset, max_size - offset, "}}"); + + EVEL_EXIT(); + + return offset; +} + +/**************************************************************************//** + * Encode a throttling specification for a domain. + * + * @param json Pointer to where to store the JSON encoded data. + * @param max_size Size of storage available in json_body. + * @returns Number of bytes actually written. + *****************************************************************************/ +int evel_json_encode_throttle_spec(char * const json, + const int max_size, + const EVEL_EVENT_DOMAINS domain) +{ + int offset; + EVEL_THROTTLE_SPEC * throttle_spec; + DLIST_ITEM * dlist_item; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(domain >= EVEL_DOMAIN_FAULT); + assert(domain < EVEL_MAX_DOMAINS); + assert(evel_throttle_spec[domain] != NULL); + + throttle_spec = evel_throttle_spec[domain]; + + /***************************************************************************/ + /* Encode the domain. */ + /***************************************************************************/ + offset = 0; + offset += snprintf(json + offset, max_size - offset, + "{"); + offset += snprintf(json + offset, max_size - offset, + "\"eventDomain\": \"%s\"", + evel_domain_strings[domain]); + + /***************************************************************************/ + /* Encode "suppressedFieldNames". */ + /***************************************************************************/ + dlist_item = dlist_get_first(&throttle_spec->suppressed_field_names); + if (dlist_item != NULL) + { + offset += snprintf(json + offset, max_size - offset, + ", \"suppressedFieldNames\": ["); + while (dlist_item != NULL) + { + char * suppressed_field = dlist_item->item; + assert(suppressed_field != NULL); + + offset += snprintf(json + offset, max_size - offset, + "\"%s\"", suppressed_field); + dlist_item = dlist_get_next(dlist_item); + if (dlist_item != NULL) + { + offset += snprintf(json + offset, max_size - offset, ", "); + } + } + + offset += snprintf(json + offset, max_size - offset, "]"); + } + + /***************************************************************************/ + /* Encode "suppressedNvPairsList". */ + /***************************************************************************/ + dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list); + if (dlist_item != NULL) + { + offset += snprintf(json + offset, max_size - offset, + ", \"suppressedNvPairsList\": ["); + while (dlist_item != NULL) + { + offset += evel_json_encode_nv_pairs(json + offset, + max_size - offset, + dlist_item->item); + dlist_item = dlist_get_next(dlist_item); + if (dlist_item != NULL) + { + offset += snprintf(json + offset, max_size - offset, ", "); + } + } + + offset += snprintf(json + offset, max_size - offset, "]"); + } + + offset += snprintf(json + offset, max_size - offset, "}"); + + EVEL_EXIT(); + + return offset; +} + +/**************************************************************************//** + * Encode a single "suppressedNvPairsListEntry". + * + * @param json Pointer to where to store the JSON encoded data. + * @param max_size Size of storage available in json_body. + * @returns Number of bytes actually written. + *****************************************************************************/ +int evel_json_encode_nv_pairs(char * const json, + const int max_size, + EVEL_SUPPRESSED_NV_PAIRS * nv_pairs) +{ + DLIST_ITEM * dlist_item; + char * name; + int offset; + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(nv_pairs != NULL); + assert(nv_pairs->nv_pair_field_name != NULL); + assert(!dlist_is_empty(&nv_pairs->suppressed_nv_pair_names)); + + /***************************************************************************/ + /* Encode it. */ + /***************************************************************************/ + offset = 0; + offset += snprintf(json + offset, max_size - offset, "{"); + offset += snprintf(json + offset, max_size - offset, + "\"nvPairFieldName\": \"%s\"", + nv_pairs->nv_pair_field_name); + dlist_item = dlist_get_first(&nv_pairs->suppressed_nv_pair_names); + offset += snprintf(json + offset, max_size - offset, + ", \"suppressedNvPairNames\": ["); + while (dlist_item != NULL) + { + name = dlist_item->item; + assert(name != NULL); + offset += snprintf(json + offset, max_size - offset, "\"%s\"", name); + dlist_item = dlist_get_next(dlist_item); + if (dlist_item != NULL) + { + offset += snprintf(json + offset, max_size - offset, ", "); + } + } + offset += snprintf(json + offset, max_size - offset, "]"); + offset += snprintf(json + offset, max_size - offset, "}"); + + EVEL_EXIT(); + + return offset; +} + +/**************************************************************************//** + * Method called when we open a "command" object. + *****************************************************************************/ +void evel_open_command() +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Make some assertions. */ + /***************************************************************************/ + assert(evel_command_type_value == NULL); + assert(evel_measurement_interval_value == NULL); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Method called when we close a "command" object. + *****************************************************************************/ +void evel_close_command() +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* If a commandType was provided, fan out and handle it now what we have */ + /* fathered all related information. */ + /* */ + /* Note that we handle throttling specification and measurement interval */ + /* updates immediately on closing the command (not the list). We could */ + /* reject *all* commands in a list if any of them are invalid, but we are */ + /* take a best-effort strategy here - any valid-looking command gets */ + /* implemented regardless of what follows. */ + /***************************************************************************/ + if (evel_command_type_value != NULL) + { + EVEL_DEBUG("Closing command %s", evel_command_type_value); + + if (strcmp(evel_command_type_value, "provideThrottlingState") == 0) + { + evel_provide_throttling_state = true; + } + else if (strcmp(evel_command_type_value, "throttlingSpecification") == 0) + { + evel_set_throttling_spec(); + } + else if (strcmp(evel_command_type_value, "measurementIntervalChange") == 0) + { + evel_set_measurement_interval(); + } + else + { + EVEL_ERROR("Ignoring unknown commandType: %s\n", + evel_command_type_value); + } + + /*************************************************************************/ + /* Free the captured "commandType" value. */ + /*************************************************************************/ + free(evel_command_type_value); + evel_command_type_value = NULL; + } + + /***************************************************************************/ + /* There could be an unused working throttle spec at this point - if the */ + /* "throttlingSpecification" commandType was not provided, or an invalid */ + /* domain was provided, or was not provided at all. */ + /***************************************************************************/ + if (evel_temp_throttle != NULL) + { + evel_throttle_free(evel_temp_throttle); + evel_temp_throttle = NULL; + } + + /***************************************************************************/ + /* Similarly, the domain could be set. */ + /***************************************************************************/ + evel_throttle_spec_domain = EVEL_MAX_DOMAINS; + + /***************************************************************************/ + /* There could be an unused measurement interval value at this point - if */ + /* the "measurementIntervalChange" command was not provided. */ + /***************************************************************************/ + if (evel_measurement_interval_value != NULL) + { + free(evel_measurement_interval_value); + evel_measurement_interval_value = NULL; + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the provided throttling specification, when the command closes. + *****************************************************************************/ +void evel_set_throttling_spec() +{ + EVEL_ENTER(); + + if ((evel_throttle_spec_domain >= 0) && + (evel_throttle_spec_domain < EVEL_MAX_DOMAINS)) + { + EVEL_DEBUG("Updating throttle spec for domain: %s", + evel_domain_strings[evel_throttle_spec_domain]); + + /*************************************************************************/ + /* Free off the previous throttle specification for the domain, if there */ + /* is one. */ + /*************************************************************************/ + if (evel_throttle_spec[evel_throttle_spec_domain] != NULL) + { + evel_throttle_free(evel_throttle_spec[evel_throttle_spec_domain]); + } + + /*************************************************************************/ + /* Finalize the working throttling spec, if there is one. */ + /*************************************************************************/ + if (evel_temp_throttle != NULL) + { + evel_throttle_finalize(evel_temp_throttle); + } + + /*************************************************************************/ + /* Replace the throttle specification for the domain with the working */ + /* throttle specification. This could be NULL, if an empty throttle */ + /* specification has been received for a domain. */ + /*************************************************************************/ + evel_throttle_spec[evel_throttle_spec_domain] = evel_temp_throttle; + evel_temp_throttle = NULL; + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the provided measurement interval, when the command closes. + *****************************************************************************/ +void evel_set_measurement_interval() +{ + EVEL_ENTER(); + + if (evel_measurement_interval_value != NULL) + { + const long int value = strtol(evel_measurement_interval_value, NULL, 10); + + if ((value >= 0) && (value <= INT_MAX)) + { + /***********************************************************************/ + /* Lock, update, unlock. */ + /***********************************************************************/ + EVEL_DEBUG("Updating measurement interval to %d\n", value); + + pthread_mutex_lock(&evel_measurement_interval_mutex); + evel_measurement_interval = value; + pthread_mutex_unlock(&evel_measurement_interval_mutex); + } + else + { + EVEL_ERROR("Ignoring invalid measurement interval: %s", + evel_measurement_interval_value); + } + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Method called when we open an "eventDomainThrottleSpecification" object. + *****************************************************************************/ +void evel_open_throttle_spec() +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(evel_throttle_spec_domain_value == NULL); + assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS); + assert(evel_temp_throttle == NULL); + + /***************************************************************************/ + /* Allocate and initialize an ::EVEL_THROTTLE_SPEC in which to hold */ + /* captured JSON elements. */ + /***************************************************************************/ + evel_temp_throttle = malloc(sizeof(EVEL_THROTTLE_SPEC)); + assert(evel_temp_throttle != NULL); + dlist_initialize(&evel_temp_throttle->suppressed_field_names); + dlist_initialize(&evel_temp_throttle->suppressed_nv_pairs_list); + evel_temp_throttle->hash_field_names = NULL; + evel_temp_throttle->hash_nv_pairs_list = NULL; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Method called when we close an "eventDomainThrottleSpecification" object. + *****************************************************************************/ +void evel_close_throttle_spec() +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Decode, free and blank a captured event domain value. */ + /***************************************************************************/ + if (evel_throttle_spec_domain_value != NULL) + { + evel_throttle_spec_domain = + evel_decode_domain(evel_throttle_spec_domain_value); + free(evel_throttle_spec_domain_value); + evel_throttle_spec_domain_value = NULL; + } + + /***************************************************************************/ + /* Free off an empty working throttle spec, to stop it being used. This */ + /* state should be represented by a NULL pointer for the domain. */ + /***************************************************************************/ + if (evel_temp_throttle != NULL) + { + if (dlist_is_empty(&evel_temp_throttle->suppressed_field_names) && + dlist_is_empty(&evel_temp_throttle->suppressed_nv_pairs_list)) + { + free(evel_temp_throttle); + evel_temp_throttle = NULL; + } + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Convert a value for an "eventDomain" into an ::EVEL_EVENT_DOMAINS. + * + * @param domain_value The domain string value to decode. + * @returns The matching ::EVEL_EVENT_DOMAINS, or ::EVEL_MAX_DOMAINS on error. + *****************************************************************************/ +EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value) +{ + EVEL_EVENT_DOMAINS result; + int ii; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(domain_value != NULL); + + result = EVEL_MAX_DOMAINS; + for (ii = EVEL_DOMAIN_FAULT; ii < EVEL_MAX_DOMAINS; ii++) + { + assert(evel_domain_strings[ii] != NULL); + if (strcmp(evel_domain_strings[ii], domain_value) == 0) + { + result = ii; + } + } + + EVEL_EXIT(); + + return result; +} + +/**************************************************************************//** + * Method called when we open a "suppressedNvPairsListEntry" object. + *****************************************************************************/ +void evel_open_nv_pairs_list_entry() +{ + EVEL_SUPPRESSED_NV_PAIRS * nv_pairs; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(evel_temp_throttle != NULL); + + /***************************************************************************/ + /* Allocate and initialize an ::EVEL_SUPPRESSED_NV_PAIRS, and add it to */ + /* the list. */ + /***************************************************************************/ + nv_pairs = malloc(sizeof(EVEL_SUPPRESSED_NV_PAIRS)); + assert(nv_pairs != NULL); + nv_pairs->nv_pair_field_name = NULL; + dlist_initialize(&nv_pairs->suppressed_nv_pair_names); + nv_pairs->hash_nv_pair_names = NULL; + dlist_push_last(&evel_temp_throttle->suppressed_nv_pairs_list, nv_pairs); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Method called when we close a "suppressedNvPairsListEntry" object. + *****************************************************************************/ +void evel_close_nv_pairs_list_entry() +{ + EVEL_SUPPRESSED_NV_PAIRS * nv_pairs; + EVEL_SUPPRESSED_NV_PAIRS * popped; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Get the latest nv pairs. This also performs the required checks. */ + /***************************************************************************/ + nv_pairs = evel_get_last_nv_pairs(); + + /***************************************************************************/ + /* For a "suppressedNvPairsListEntry" to have any meaning, we need both */ + /* "nvPairFieldName" and "suppressedNvPairNames". If we don't, then pop */ + /* and free whatever we just collected. */ + /***************************************************************************/ + if ((nv_pairs->nv_pair_field_name == NULL) || + dlist_is_empty(&nv_pairs->suppressed_nv_pair_names)) + { + popped = dlist_pop_last(&evel_temp_throttle->suppressed_nv_pairs_list); + assert(popped == nv_pairs); + evel_throttle_free_nv_pair(popped); + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Store an "nvPairFieldName" value in the working throttle spec. + * + * @param value The value to store. + *****************************************************************************/ +void evel_store_nv_pair_field_name(char * const value) +{ + EVEL_SUPPRESSED_NV_PAIRS * nv_pairs; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Get the latest nv pairs. This also performs the required checks. */ + /***************************************************************************/ + nv_pairs = evel_get_last_nv_pairs(); + + /***************************************************************************/ + /* Store the value. */ + /***************************************************************************/ + nv_pairs->nv_pair_field_name = value; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Store a "suppressedNvPairNames" item in the working throttle spec. + * + * @param item The item to store. + *****************************************************************************/ +void evel_store_nv_pair_name(char * const item) +{ + EVEL_SUPPRESSED_NV_PAIRS * nv_pairs; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Get the latest nv pairs. This also performs the required checks. */ + /***************************************************************************/ + nv_pairs = evel_get_last_nv_pairs(); + + /***************************************************************************/ + /* Store the item. */ + /***************************************************************************/ + dlist_push_last(&nv_pairs->suppressed_nv_pair_names, item); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Store a "suppressedFieldNames" item in the working throttle spec. + * + * @param item The item to store. + *****************************************************************************/ +void evel_store_suppressed_field_name(char * const item) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(evel_temp_throttle != NULL); + + /***************************************************************************/ + /* Store the item. */ + /***************************************************************************/ + dlist_push_last(&evel_temp_throttle->suppressed_field_names, item); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Get the last added suppressed nv pairs list entry in the working spec. + * + * @returns The last entry. + *****************************************************************************/ +EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs() +{ + DLIST_ITEM * dlist_item; + EVEL_SUPPRESSED_NV_PAIRS * nv_pairs; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(evel_temp_throttle != NULL); + + /***************************************************************************/ + /* Get the pair that was added when we opened the list entry. */ + /***************************************************************************/ + dlist_item = dlist_get_last(&evel_temp_throttle->suppressed_nv_pairs_list); + assert(dlist_item != NULL); + nv_pairs = dlist_item->item; + assert(nv_pairs != NULL); + + EVEL_EXIT(); + + return nv_pairs; +} diff --git a/vnfs/VES/code/evel_library/evel_throttle.h b/vnfs/VES/code/evel_library/evel_throttle.h new file mode 100644 index 00000000..5f02cd2f --- /dev/null +++ b/vnfs/VES/code/evel_library/evel_throttle.h @@ -0,0 +1,228 @@ +#ifndef EVEL_THROTTLE_INCLUDED +#define EVEL_THROTTLE_INCLUDED + +/**************************************************************************//** + * @file + * EVEL throttle definitions. + * + * These are internal definitions related to throttling specicications, which + * are required within the library but are not intended for external + * consumption. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include "evel_internal.h" +#include "jsmn.h" + +/*****************************************************************************/ +/* Maximum depth of JSON response that we can handle. */ +/*****************************************************************************/ +#define EVEL_JSON_STACK_DEPTH 10 + +/**************************************************************************//** + * Maximum number of tokens that we allow for in a JSON response. + *****************************************************************************/ +#define EVEL_MAX_RESPONSE_TOKENS 1024 + +/**************************************************************************//** + * The nature of the next token that we are iterating through. Within an + * object, we alternate between collecting keys and values. Within an array, + * we only collect items. + *****************************************************************************/ +typedef enum { + EVEL_JSON_KEY, + EVEL_JSON_VALUE, + EVEL_JSON_ITEM +} EVEL_JSON_STATE; + +/**************************************************************************//** + * States which we move through during JSON processing, tracking our way + * through the supported JSON structure. + *****************************************************************************/ +typedef enum +{ + /***************************************************************************/ + /* Initial state. */ + /***************************************************************************/ + EVEL_JCS_START, + + /***************************************************************************/ + /* {"commandList": [ */ + /***************************************************************************/ + EVEL_JCS_COMMAND_LIST, + + /***************************************************************************/ + /* {"commandList": [{ */ + /***************************************************************************/ + EVEL_JCS_COMMAND_LIST_ENTRY, + + /***************************************************************************/ + /* {"commandList": [{"command": { */ + /***************************************************************************/ + EVEL_JCS_COMMAND, + + /***************************************************************************/ + /* ... "eventDomainThrottleSpecification": { */ + /***************************************************************************/ + EVEL_JCS_SPEC, + + /***************************************************************************/ + /* ... "suppressedFieldNames": [ */ + /***************************************************************************/ + EVEL_JCS_FIELD_NAMES, + + /***************************************************************************/ + /* ... "suppressedNvPairsList": [ */ + /***************************************************************************/ + EVEL_JCS_PAIRS_LIST, + + /***************************************************************************/ + /* ... "suppressedNvPairsList": [{ */ + /***************************************************************************/ + EVEL_JCS_PAIRS_LIST_ENTRY, + + /***************************************************************************/ + /* ... "suppressedNvPairNames": [ */ + /***************************************************************************/ + EVEL_JCS_NV_PAIR_NAMES, + + EVEL_JCS_MAX +} EVEL_JSON_COMMAND_STATE; + +/**************************************************************************//** + * An entry in the JSON stack. + *****************************************************************************/ +typedef struct evel_json_stack_entry { + + /***************************************************************************/ + /* The number of elements required at this level. */ + /***************************************************************************/ + int num_required; + + /***************************************************************************/ + /* The number of elements collected at this level. */ + /***************************************************************************/ + int json_count; + + /***************************************************************************/ + /* The collection state at this level in the JSON stack. */ + /***************************************************************************/ + EVEL_JSON_STATE json_state; + + /***************************************************************************/ + /* The key being collected (if json_state is EVEL_JSON_VALUE), or NULL. */ + /***************************************************************************/ + char * json_key; + +} EVEL_JSON_STACK_ENTRY; + +/**************************************************************************//** + * The JSON stack. + *****************************************************************************/ +typedef struct evel_json_stack { + + /***************************************************************************/ + /* The current position of the stack - starting at zero. */ + /***************************************************************************/ + int level; + + /***************************************************************************/ + /* The stack itself. */ + /***************************************************************************/ + EVEL_JSON_STACK_ENTRY entry[EVEL_JSON_STACK_DEPTH]; + + /***************************************************************************/ + /* The underlying memory chunk. */ + /***************************************************************************/ + const MEMORY_CHUNK * chunk; + +} EVEL_JSON_STACK; + +/**************************************************************************//** + * Initialize event throttling to the default state. + * + * Called from ::evel_initialize. + *****************************************************************************/ +void evel_throttle_initialize(); + +/**************************************************************************//** + * Clean up event throttling. + * + * Called from ::evel_terminate. + *****************************************************************************/ +void evel_throttle_terminate(); + +/**************************************************************************//** + * Handle a JSON response from the listener, as a list of tokens from JSMN. + * + * @param chunk Memory chunk containing the JSON buffer. + * @param json_tokens Array of tokens to handle. + * @param num_tokens The number of tokens to handle. + * @param post The memory chunk in which to place any resulting POST. + * @return true if the command was handled, false otherwise. + *****************************************************************************/ +bool evel_handle_command_list(const MEMORY_CHUNK * const chunk, + const jsmntok_t * const json_tokens, + const int num_tokens, + MEMORY_CHUNK * const post); + +/**************************************************************************//** + * Return the ::EVEL_THROTTLE_SPEC for a given domain. + * + * @param domain The domain for which to return state. + *****************************************************************************/ +EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain); + +/**************************************************************************//** + * Determine whether a field_name should be suppressed. + * + * @param throttle_spec Throttle specification for the domain being encoded. + * @param field_name The field name to encoded or suppress. + * @return true if the field_name should be suppressed, false otherwise. + *****************************************************************************/ +bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC * throttle_spec, + const char * const field_name); + +/**************************************************************************//** + * Determine whether a name-value pair should be allowed (not suppressed). + * + * @param throttle_spec Throttle specification for the domain being encoded. + * @param field_name The field name holding the name-value pairs. + * @param name The name of the name-value pair to encoded or suppress. + * @return true if the name-value pair should be suppressed, false otherwise. + *****************************************************************************/ +bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC * throttle_spec, + const char * const field_name, + const char * const name); + +#endif diff --git a/vnfs/VES/code/evel_library/jsmn.c b/vnfs/VES/code/evel_library/jsmn.c new file mode 100644 index 00000000..e7765eb1 --- /dev/null +++ b/vnfs/VES/code/evel_library/jsmn.c @@ -0,0 +1,311 @@ +#include "jsmn.h" + +/** + * Allocates a fresh unused token from the token pull. + */ +static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, + jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *tok; + if (parser->toknext >= num_tokens) { + return NULL; + } + tok = &tokens[parser->toknext++]; + tok->start = tok->end = -1; + tok->size = 0; +#ifdef JSMN_PARENT_LINKS + tok->parent = -1; +#endif + return tok; +} + +/** + * Fills token type and boundaries. + */ +static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, + int start, int end) { + token->type = type; + token->start = start; + token->end = end; + token->size = 0; +} + +/** + * Fills next available token with JSON primitive. + */ +static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *token; + int start; + + start = parser->pos; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + switch (js[parser->pos]) { +#ifndef JSMN_STRICT + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': +#endif + case '\t' : case '\r' : case '\n' : case ' ' : + case ',' : case ']' : case '}' : + goto found; + } + if (js[parser->pos] < 32 || js[parser->pos] >= 127) { + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } +#ifdef JSMN_STRICT + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; +#endif + +found: + if (tokens == NULL) { + parser->pos--; + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + parser->pos--; + return 0; +} + +/** + * Fills next token with JSON string. + */ +static int jsmn_parse_string(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *token; + + int start = parser->pos; + + parser->pos++; + + /* Skip starting quote */ + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c = js[parser->pos]; + + /* Quote: end of string */ + if (c == '\"') { + if (tokens == NULL) { + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + return 0; + } + + /* Backslash: Quoted symbol expected */ + if (c == '\\' && parser->pos + 1 < len) { + int i; + parser->pos++; + switch (js[parser->pos]) { + /* Allowed escaped symbols */ + case '\"': case '/' : case '\\' : case 'b' : + case 'f' : case 'r' : case 'n' : case 't' : + break; + /* Allows escaped symbol \uXXXX */ + case 'u': + parser->pos++; + for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { + /* If it isn't a hex character we have an error */ + if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ + (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ + (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ + parser->pos = start; + return JSMN_ERROR_INVAL; + } + parser->pos++; + } + parser->pos--; + break; + /* Unexpected symbol */ + default: + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } + } + parser->pos = start; + return JSMN_ERROR_PART; +} + +/** + * Parse JSON string and fill tokens. + */ +int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens) { + int r; + int i; + jsmntok_t *token; + int count = parser->toknext; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c; + jsmntype_t type; + + c = js[parser->pos]; + switch (c) { + case '{': case '[': + count++; + if (tokens == NULL) { + break; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) + return JSMN_ERROR_NOMEM; + if (parser->toksuper != -1) { + tokens[parser->toksuper].size++; +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + break; + case '}': case ']': + if (tokens == NULL) + break; + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); +#ifdef JSMN_PARENT_LINKS + if (parser->toknext < 1) { + return JSMN_ERROR_INVAL; + } + token = &tokens[parser->toknext - 1]; + for (;;) { + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + token->end = parser->pos + 1; + parser->toksuper = token->parent; + break; + } + if (token->parent == -1) { + break; + } + token = &tokens[token->parent]; + } +#else + for (i = parser->toknext - 1; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) return JSMN_ERROR_INVAL; + for (; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + parser->toksuper = i; + break; + } + } +#endif + break; + case '\"': + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + case '\t' : case '\r' : case '\n' : case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && parser->toksuper != -1 && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) { +#ifdef JSMN_PARENT_LINKS + parser->toksuper = tokens[parser->toksuper].parent; +#else + for (i = parser->toknext - 1; i >= 0; i--) { + if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { + if (tokens[i].start != -1 && tokens[i].end == -1) { + parser->toksuper = i; + break; + } + } + } +#endif + } + break; +#ifdef JSMN_STRICT + /* In strict mode primitives are: numbers and booleans */ + case '-': case '0': case '1' : case '2': case '3' : case '4': + case '5': case '6': case '7' : case '8': case '9': + case 't': case 'f': case 'n' : + /* And they must not be keys of the object */ + if (tokens != NULL && parser->toksuper != -1) { + jsmntok_t *t = &tokens[parser->toksuper]; + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) { + return JSMN_ERROR_INVAL; + } + } +#else + /* In non-strict mode every unquoted value is a primitive */ + default: +#endif + r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + +#ifdef JSMN_STRICT + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; +#endif + } + } + + if (tokens != NULL) { + for (i = parser->toknext - 1; i >= 0; i--) { + /* Unmatched opened object or array */ + if (tokens[i].start != -1 && tokens[i].end == -1) { + return JSMN_ERROR_PART; + } + } + } + + return count; +} + +/** + * Creates a new parser based over a given buffer with an array of tokens + * available. + */ +void jsmn_init(jsmn_parser *parser) { + parser->pos = 0; + parser->toknext = 0; + parser->toksuper = -1; +} + diff --git a/vnfs/VES/code/evel_library/jsmn.h b/vnfs/VES/code/evel_library/jsmn.h new file mode 100644 index 00000000..01ca99c8 --- /dev/null +++ b/vnfs/VES/code/evel_library/jsmn.h @@ -0,0 +1,76 @@ +#ifndef __JSMN_H_ +#define __JSMN_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * JSON type identifier. Basic types are: + * o Object + * o Array + * o String + * o Other primitive: number, boolean (true/false) or null + */ +typedef enum { + JSMN_UNDEFINED = 0, + JSMN_OBJECT = 1, + JSMN_ARRAY = 2, + JSMN_STRING = 3, + JSMN_PRIMITIVE = 4 +} jsmntype_t; + +enum jsmnerr { + /* Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /* Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /* The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 +}; + +/** + * JSON token description. + * @param type type (object, array, string etc.) + * @param start start position in JSON data string + * @param end end position in JSON data string + */ +typedef struct { + jsmntype_t type; + int start; + int end; + int size; +#ifdef JSMN_PARENT_LINKS + int parent; +#endif +} jsmntok_t; + +/** + * JSON parser. Contains an array of token blocks available. Also stores + * the string being parsed now and current position in that string + */ +typedef struct { + unsigned int pos; /* offset in the JSON string */ + unsigned int toknext; /* next token to allocate */ + int toksuper; /* superior token node, e.g parent object or array */ +} jsmn_parser; + +/** + * Create JSON parser over an array of tokens + */ +void jsmn_init(jsmn_parser *parser); + +/** + * Run JSON parser. It parses a JSON data string into and array of tokens, each describing + * a single JSON object. + */ +int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens); + +#ifdef __cplusplus +} +#endif + +#endif /* __JSMN_H_ */ diff --git a/vnfs/VES/code/evel_library/license.md b/vnfs/VES/code/evel_library/license.md new file mode 100644 index 00000000..9851dcac --- /dev/null +++ b/vnfs/VES/code/evel_library/license.md @@ -0,0 +1,95 @@ +# Licensing {#licensing} + +# Introduction {#lic_intro} + +This Licensing section describes licensing of IPR in the EVEL Library. + +# Licensed Software {#lic_software} + +## EVEL Library {#lic_evel} + +Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: This product includes + software developed by the AT&T. +4. Neither the name of AT&T nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## libcurl {#lic_libcurl} + +The EVEL Library makes use of the the [cURL Library] +(https://curl.haxx.se/libcurl/) in order to send and receive HTTP data. + +### License + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1996 - 2016, Daniel Stenberg, daniel@haxx.se, and many +contributors, see the THANKS file. + +All rights reserved. + +Permission to use, copy, modify, and distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall not be +used in advertising or otherwise to promote the sale, use or other dealings in +this Software without prior written authorization of the copyright holder. + +## JSMN {#lic_jsmn} + +The EVEL Library makes use of the [JSMN library](http://zserge.com/jsmn.html) +in order to decode JSON data. + +### License {#lic_jsmn_license} + +Copyright (c) 2010 Serge A. Zaitsev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + \ No newline at end of file diff --git a/vnfs/VES/code/evel_library/metadata.c b/vnfs/VES/code/evel_library/metadata.c new file mode 100644 index 00000000..dfdca052 --- /dev/null +++ b/vnfs/VES/code/evel_library/metadata.c @@ -0,0 +1,607 @@ +/**************************************************************************//** + * @file + * Wrap the OpenStack metadata service. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include +#include + +#include + +#include "evel.h" +#include "evel_internal.h" +#include "jsmn.h" +#include "metadata.h" + +/**************************************************************************//** + * URL on the link-local IP address where we can get the metadata in + * machine-friendly format. + *****************************************************************************/ +static const char * OPENSTACK_METADATA_URL = + "http://169.254.169.254/openstack/latest/meta_data.json"; + +/**************************************************************************//** + * How long we're prepared to wait for the metadata service to respond in + * seconds. + *****************************************************************************/ +static const int OPENSTACK_METADATA_TIMEOUT = 2; + +/**************************************************************************//** + * Size of fields extracted from metadata service. + *****************************************************************************/ +#define MAX_METADATA_STRING 64 + +/**************************************************************************//** + * UUID of the VM extracted from the OpenStack metadata service. + *****************************************************************************/ +static char vm_uuid[MAX_METADATA_STRING+1] = {0}; + +/**************************************************************************//** + * Name of the VM extracted from the OpenStack metadata service. + *****************************************************************************/ +static char vm_name[MAX_METADATA_STRING+1] = {0}; + +/**************************************************************************//** + * How many metadata elements we allow for in the retrieved JSON. + *****************************************************************************/ +static const int MAX_METADATA_TOKENS = 128; + +/*****************************************************************************/ +/* Local prototypes. */ +/*****************************************************************************/ +static EVEL_ERR_CODES json_get_top_level_string(const char * json_string, + const jsmntok_t *tokens, + int json_token_count, + const char * key, + char * value); +static EVEL_ERR_CODES json_get_string(const char * json_string, + const jsmntok_t *tokens, + int json_token_count, + const char * key, + char * value); +static int jsoneq(const char *json, const jsmntok_t *tok, const char *s); + +/**************************************************************************//** + * Download metadata from the OpenStack metadata service. + * + * @param verbosity Controls whether to generate debug to stdout. Zero: + * none. Non-zero: generate debug. + * @returns Status code + * @retval EVEL_SUCCESS On success + * @retval ::EVEL_ERR_CODES On failure. + *****************************************************************************/ +EVEL_ERR_CODES openstack_metadata(int verbosity) +{ + int rc = EVEL_SUCCESS; + CURLcode curl_rc = CURLE_OK; + CURL * curl_handle = NULL; + MEMORY_CHUNK rx_chunk; + char curl_err_string[CURL_ERROR_SIZE] = ""; + jsmn_parser json_parser; + jsmntok_t tokens[MAX_METADATA_TOKENS]; + int json_token_count = 0; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Initialize dummy values for the metadata - needed for test */ + /* environments. */ + /***************************************************************************/ + openstack_metadata_initialize(); + + /***************************************************************************/ + /* Get a curl handle which we'll use for accessing the metadata service. */ + /***************************************************************************/ + curl_handle = curl_easy_init(); + if (curl_handle == NULL) + { + rc = EVEL_CURL_LIBRARY_FAIL; + EVEL_ERROR("Failed to get libcurl handle"); + goto exit_label; + } + + /***************************************************************************/ + /* Prime the library to give friendly error codes. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, + CURLOPT_ERRORBUFFER, + curl_err_string); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + EVEL_ERROR("Failed to initialize libcurl to provide friendly errors. " + "Error code=%d", curl_rc); + goto exit_label; + } + + /***************************************************************************/ + /* Set the URL for the metadata API. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, OPENSTACK_METADATA_URL); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + EVEL_ERROR("Failed to initialize libcurl with the API URL. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + + /***************************************************************************/ + /* send all data to this function. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, + CURLOPT_WRITEFUNCTION, + evel_write_callback); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + EVEL_ERROR("Failed to initialize libcurl with the write callback. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + + /***************************************************************************/ + /* some servers don't like requests that are made without a user-agent */ + /* field, so we provide one. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, + CURLOPT_USERAGENT, + "libcurl-agent/1.0"); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + EVEL_ERROR("Failed to initialize libcurl to upload. Error code=%d (%s)", + curl_rc, curl_err_string); + goto exit_label; + } + + /***************************************************************************/ + /* Set the timeout for the operation. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, + CURLOPT_TIMEOUT, + OPENSTACK_METADATA_TIMEOUT); + if (curl_rc != CURLE_OK) + { + rc = EVEL_NO_METADATA; + EVEL_ERROR("Failed to initialize libcurl to set timeout. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + + /***************************************************************************/ + /* Create the memory chunk to be used for the response to the post. The */ + /* will be realloced. */ + /***************************************************************************/ + rx_chunk.memory = malloc(1); + assert(rx_chunk.memory != NULL); + rx_chunk.size = 0; + + /***************************************************************************/ + /* Point to the data to be received. */ + /***************************************************************************/ + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&rx_chunk); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + EVEL_ERROR("Failed to initialize libcurl to receive metadata. " + "Error code=%d (%s)", curl_rc, curl_err_string); + goto exit_label; + } + EVEL_DEBUG("Initialized data to receive"); + + /***************************************************************************/ + /* If running in verbose mode generate more output. */ + /***************************************************************************/ + if (verbosity > 0) + { + curl_rc = curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + log_error_state("Failed to initialize libcurl to be verbose. " + "Error code=%d", curl_rc); + goto exit_label; + } + } + + /***************************************************************************/ + /* Now run off and do what you've been told! */ + /***************************************************************************/ + curl_rc = curl_easy_perform(curl_handle); + if (curl_rc != CURLE_OK) + { + rc = EVEL_CURL_LIBRARY_FAIL; + EVEL_ERROR("Failed to transfer the data from metadata service. " + "Error code=%d (%s)", curl_rc, curl_err_string); + } + else + { + /*************************************************************************/ + /* We have some metadata available, so break it out into tokens. */ + /*************************************************************************/ + EVEL_DEBUG("Received metadata size = %d", rx_chunk.size); + EVEL_INFO("Received metadata = %s", rx_chunk.memory); + jsmn_init(&json_parser); + json_token_count = jsmn_parse(&json_parser, + rx_chunk.memory, rx_chunk.size, + tokens, MAX_METADATA_TOKENS); + + /*************************************************************************/ + /* Check that we parsed some data and that the top level is as expected. */ + /*************************************************************************/ + if (json_token_count < 0 || tokens[0].type != JSMN_OBJECT) + { + rc = EVEL_BAD_METADATA; + EVEL_ERROR("Failed to parse received JSON OpenStack metadata. " + "Error code=%d", json_token_count); + goto exit_label; + } + else + { + EVEL_DEBUG("Extracted %d tokens from the JSON OpenStack metadata. ", + json_token_count); + } + + /*************************************************************************/ + /* Find the keys we want from the metadata. */ + /*************************************************************************/ + if (json_get_string(rx_chunk.memory, + tokens, + json_token_count, + "uuid", + vm_uuid) != EVEL_SUCCESS) + { + rc = EVEL_BAD_METADATA; + EVEL_ERROR("Failed to extract UUID from OpenStack metadata"); + } + else + { + EVEL_DEBUG("UUID: %s", vm_uuid); + } + if (json_get_top_level_string(rx_chunk.memory, + tokens, + json_token_count, + "name", + vm_name) != EVEL_SUCCESS) + { + rc = EVEL_BAD_METADATA; + EVEL_ERROR("Failed to extract VM Name from OpenStack metadata"); + } + else + { + EVEL_DEBUG("VM Name: %s", vm_name); + } + } + +exit_label: + + /***************************************************************************/ + /* Shut down the cURL library in a tidy manner. */ + /***************************************************************************/ + if (curl_handle != NULL) + { + curl_easy_cleanup(curl_handle); + curl_handle = NULL; + } + free(rx_chunk.memory); + + EVEL_EXIT(); + return rc; +} + +/**************************************************************************//** + * Initialize default values for vm_name and vm_uuid - for testing purposes. + *****************************************************************************/ +void openstack_metadata_initialize() +{ + strncpy(vm_uuid, + "Dummy VM UUID - No Metadata available", + MAX_METADATA_STRING); + strncpy(vm_name, + "Dummy VM name - No Metadata available", + MAX_METADATA_STRING); +} + +/**************************************************************************//** + * Get a string value from supplied JSON by matching the key. + * + * As the structure of the metadata we're looking at is pretty straightforward + * we don't do anything complex (a la XPath) to extract nested keys with the + * same leaf name, for example. Simply walk the structure until we find a + * string with the correct value. + * + * @param[in] json_string The string which contains the JSON and has already + * been parsed. + * @param[in] tokens The tokens which the JSON parser found in the JSON. + * @param[in] json_token_count How many tokens were found. + * @param[in] key The key we're looking for. + * @param[out] value The string we found at @p key. + * + * @returns Status code + * @retval EVEL_SUCCESS On success - contents of @p value updated. + * @retval EVEL_JSON_KEY_NOT_FOUND Key not found - @p value not updated. + * @retval EVEL_BAD_JSON Parser hit unexpected data - @p value not + * updated. + *****************************************************************************/ +static EVEL_ERR_CODES json_get_string(const char * json_string, + const jsmntok_t * tokens, + int json_token_count, + const char * key, + char * value) +{ + EVEL_ERR_CODES rc = EVEL_JSON_KEY_NOT_FOUND; + int token_num = 0; + int token_len = 0; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(json_string != NULL); + assert(tokens != NULL); + assert(json_token_count >= 0); + assert(key != NULL); + assert(value != NULL); + + for (token_num = 0; token_num < json_token_count; token_num++) + { + switch(tokens[token_num].type) + { + case JSMN_OBJECT: + EVEL_DEBUG("Skipping object"); + break; + + case JSMN_ARRAY: + EVEL_DEBUG("Skipping array"); + break; + + case JSMN_STRING: + /***********************************************************************/ + /* This is a string, so may be what we want. Compare keys. */ + /***********************************************************************/ + if (jsoneq(json_string, &tokens[token_num], key) == 0) + { + token_len = tokens[token_num + 1].end - tokens[token_num + 1].start; + EVEL_DEBUG("Token %d len %d matches at %d to %d", token_num, + tokens[token_num + 1].start, + tokens[token_num + 1].end); + strncpy(value, json_string + tokens[token_num + 1].start, token_len); + value[token_len] = '\0'; + EVEL_DEBUG("Extracted key: \"%s\" Value: \"%s\"", key, value); + rc = EVEL_SUCCESS; + goto exit_label; + } + else + { + EVEL_DEBUG("String key did not match"); + } + + /***********************************************************************/ + /* Step over the value, whether we used it or not. */ + /***********************************************************************/ + token_num++; + break; + + case JSMN_PRIMITIVE: + EVEL_INFO("Skipping primitive"); + break; + + case JSMN_UNDEFINED: + default: + rc = EVEL_BAD_JSON_FORMAT; + EVEL_ERROR("Unexpected JSON format at token %d (%d)", + token_num, + tokens[token_num].type); + goto exit_label; + } + } + +exit_label: + EVEL_EXIT(); + return rc; +} + +/**************************************************************************//** + * Get a top-level string value from supplied JSON by matching the key. + * + * Unlike json_get_string, this only returns a value that is in the top-level + * JSON object. + * + * @param[in] json_string The string which contains the JSON and has already + * been parsed. + * @param[in] tokens The tokens which the JSON parser found in the JSON. + * @param[in] json_token_count How many tokens were found. + * @param[in] key The key we're looking for. + * @param[out] value The string we found at @p key. + * + * @returns Status code + * @retval EVEL_SUCCESS On success - contents of @p value updated. + * @retval EVEL_JSON_KEY_NOT_FOUND Key not found - @p value not updated. + * @retval EVEL_BAD_JSON Parser hit unexpected data - @p value not + * updated. + *****************************************************************************/ +static EVEL_ERR_CODES json_get_top_level_string(const char * json_string, + const jsmntok_t * tokens, + int json_token_count, + const char * key, + char * value) +{ + EVEL_ERR_CODES rc = EVEL_JSON_KEY_NOT_FOUND; + int token_num = 0; + int token_len = 0; + int bracket_count = 0; + int string_index = 0; + int increment = 0; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(json_string != NULL); + assert(tokens != NULL); + assert(json_token_count >= 0); + assert(key != NULL); + assert(value != NULL); + + for (token_num = 0; token_num < json_token_count; token_num++) + { + switch(tokens[token_num].type) + { + case JSMN_OBJECT: + EVEL_DEBUG("Skipping object"); + break; + + case JSMN_ARRAY: + EVEL_DEBUG("Skipping array"); + break; + + case JSMN_STRING: + /***********************************************************************/ + /* This is a string, so may be what we want. Compare keys. */ + /***********************************************************************/ + if (jsoneq(json_string, &tokens[token_num], key) == 0) + { + /*********************************************************************/ + /* Count the difference in the number of opening and closing */ + /* brackets up to this token. This needs to be 1 for a top-level */ + /* string. Let's just hope we don't have any strings containing */ + /* brackets. */ + /*********************************************************************/ + increment = ((string_index < tokens[token_num].start) ? 1 : -1); + + while (string_index != tokens[token_num].start) + { + if (json_string[string_index] == '{') + { + bracket_count += increment; + } + else if (json_string[string_index] == '}') + { + bracket_count -= increment; + } + + string_index += increment; + } + + if (bracket_count == 1) + { + token_len = tokens[token_num + 1].end - tokens[token_num + 1].start; + EVEL_DEBUG("Token %d len %d matches at top level at %d to %d", + token_num, + tokens[token_num + 1].start, + tokens[token_num + 1].end); + strncpy(value, json_string + tokens[token_num + 1].start, token_len); + value[token_len] = '\0'; + EVEL_DEBUG("Extracted key: \"%s\" Value: \"%s\"", key, value); + rc = EVEL_SUCCESS; + goto exit_label; + } + else + { + EVEL_DEBUG("String key did match, but not at top level"); + } + } + else + { + EVEL_DEBUG("String key did not match"); + } + + /***********************************************************************/ + /* Step over the value, whether we used it or not. */ + /***********************************************************************/ + token_num++; + break; + + case JSMN_PRIMITIVE: + EVEL_INFO("Skipping primitive"); + break; + + case JSMN_UNDEFINED: + default: + rc = EVEL_BAD_JSON_FORMAT; + EVEL_ERROR("Unexpected JSON format at token %d (%d)", + token_num, + tokens[token_num].type); + goto exit_label; + } + } + +exit_label: + EVEL_EXIT(); + return rc; +} + +/**************************************************************************//** + * Compare a JSON string token with a value. + * + * @param[in] json The string which contains the JSON and has already been + * parsed. + * @param[in] tok The token which the JSON parser found in the JSON. + * @param[in] s The string we're looking for. + * + * @returns Whether the token matches the string or not. + * @retval 0 Value matches + * @retval -1 Value does not match. + *****************************************************************************/ +static int jsoneq(const char *json, const jsmntok_t *tok, const char *s) { + if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start && + strncmp(json + tok->start, s, tok->end - tok->start) == 0) { + return 0; + } + return -1; +} + +/**************************************************************************//** + * Get the VM name provided by the metadata service. + * + * @returns VM name + *****************************************************************************/ +const char *openstack_vm_name() +{ + return vm_name; +} + +/**************************************************************************//** + * Get the VM UUID provided by the metadata service. + * + * @returns VM UUID + *****************************************************************************/ +const char *openstack_vm_uuid() +{ + return vm_uuid; +} diff --git a/vnfs/VES/code/evel_library/metadata.h b/vnfs/VES/code/evel_library/metadata.h new file mode 100644 index 00000000..d9d0cc1a --- /dev/null +++ b/vnfs/VES/code/evel_library/metadata.h @@ -0,0 +1,72 @@ +#ifndef METADATA_INCLUDED +#define METADATA_INCLUDED +/**************************************************************************//** + * @file + * Wrap the OpenStack metadata service. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + + +#include "evel.h" + +/**************************************************************************//** + * Download metadata from the OpenStack metadata service. + * + * @param verbosity Controls whether to generate debug to stdout. Zero: + * none. Non-zero: generate debug. + * @returns Status code + * @retval EVEL_SUCCESS On success + * @retval ::EVEL_ERR_CODES On failure. + *****************************************************************************/ +EVEL_ERR_CODES openstack_metadata(int verbosity); + +/**************************************************************************//** + * Initialize default values for vm_name and vm_uuid - for testing purposes. + *****************************************************************************/ +void openstack_metadata_initialize(); + +/**************************************************************************//** + * Get the VM name provided by the metadata service. + * + * @returns VM name + *****************************************************************************/ +const char *openstack_vm_name(); + +/**************************************************************************//** + * Get the VM UUID provided by the metadata service. + * + * @returns VM UUID + *****************************************************************************/ +const char *openstack_vm_uuid(); + +#endif diff --git a/vnfs/VES/code/evel_library/quickstart.md b/vnfs/VES/code/evel_library/quickstart.md new file mode 100644 index 00000000..1c735cc4 --- /dev/null +++ b/vnfs/VES/code/evel_library/quickstart.md @@ -0,0 +1,445 @@ +# Quick Start Guide {#quickstart} + +# Introduction {#qs_intro} + +This Quick-Start section describes how to: + + * Install and compile the supplied library code + * Integrate an existing project to use the EVEL library + +# Installation {#qs_install} + +The library is supplied as a source-code compressed-tar file. It is +straightforward to install and build to integrate with an existing or new +development project. + +## Unpack the Source Code {#qs_unpack} + +The file should unpacked into your development environment: +``` +$ mkdir evel +$ cd evel +$ tar zxvf evel-library-package.tgz +``` +### Satisfy Dependencies {#qs_depend} + +Note that all commands in this section are based on CentOS package management +tools and you may need to substitute the appropriate tools/packages for your +distribution, for example `apt-get` for Ubuntu. + +Ensure that GCC development tools are available. + +``` +$ sudo yum install gcc +``` +Additionally, the library has a dependency on the cURL library, so you'll need +the development tools for libCurl installed. (At runtime, only the runtime +library is required, of course.) + +``` +$ sudo yum install libcurl-devel +``` +If you wish to make the project documentation, then Doxygen and Graphviz are +required. (Again, this is only in the development environment, not the runtime +environment!) + +``` +$ sudo yum install doxygen graphviz +``` + +Note that some distributions have quite old versions of Doxygen by default and +it may be necessary to install a later version to use all the features. + +If you want to build PDFs from the LaTeX you will need a texlive install. + +``` +$ sudo yum install texlive +``` + +### Test Build {#qs_build} +Make sure that the library makes cleanly: + +``` +$ cd bldjobs +$ make +Making dependency file evel_unit.d for evel_unit.c +Making dependency file evel_test_control.d for evel_test_control.c +Making dependency file evel_demo.d for evel_demo.c +Making dependency file jsmn.d for jsmn.c +Making dependency file evel_logging.d for evel_logging.c +Making dependency file evel_event_mgr.d for evel_event_mgr.c +Making dependency file evel_internal_event.d for evel_internal_event.c +Making dependency file evel_throttle.d for evel_throttle.c +Making dependency file evel_syslog.d for evel_syslog.c +Making dependency file evel_strings.d for evel_strings.c +Making dependency file evel_state_change.d for evel_state_change.c +Making dependency file evel_scaling_measurement.d for evel_scaling_measurement.c +Making dependency file evel_signaling.d for evel_signaling.c +Making dependency file evel_service.d for evel_service.c +Making dependency file evel_reporting_measurement.d for evel_reporting_measurement.c +Making dependency file evel_json_buffer.d for evel_json_buffer.c +Making dependency file evel_other.d for evel_other.c +Making dependency file evel_option.d for evel_option.c +Making dependency file evel_mobile_flow.d for evel_mobile_flow.c +Making dependency file evel_fault.d for evel_fault.c +Making dependency file evel_event.d for evel_event.c +Making dependency file double_list.d for double_list.c +Making dependency file ring_buffer.d for ring_buffer.c +Making dependency file metadata.d for metadata.c +Making dependency file evel.d for evel.c +Making evel.o from evel.c +Making metadata.o from metadata.c +Making ring_buffer.o from ring_buffer.c +Making double_list.o from double_list.c +Making evel_event.o from evel_event.c +Making evel_fault.o from evel_fault.c +Making evel_mobile_flow.o from evel_mobile_flow.c +Making evel_option.o from evel_option.c +Making evel_other.o from evel_other.c +Making evel_json_buffer.o from evel_json_buffer.c +Making evel_reporting_measurement.o from evel_reporting_measurement.c +Making evel_service.o from evel_service.c +Making evel_signaling.o from evel_signaling.c +Making evel_scaling_measurement.o from evel_scaling_measurement.c +Making evel_state_change.o from evel_state_change.c +Making evel_strings.o from evel_strings.c +Making evel_syslog.o from evel_syslog.c +Making evel_throttle.o from evel_throttle.c +Making evel_internal_event.o from evel_internal_event.c +Making evel_event_mgr.o from evel_event_mgr.c +Making evel_logging.o from evel_logging.c +Making jsmn.o from jsmn.c +Linking API Shared Library +Linking API Static Library +Making evel_demo.o from evel_demo.c +Making evel_test_control.o from evel_test_control.c +Linking EVEL demo +Making EVEL training +$ +``` +You should now be able to run the demo CLI application. Since it will want to +dynamically link to the library that you've just made, you will need to set +your `LD_LIBRARY_PATH` appropriately first. Make sure that you specify +your actual directory paths correctly in the following: + +``` +$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/centos/evel/libs/x86_64 +$ ../output/x86_64/evel_demo +evel_demo [--help] + --fqdn + --port + [--path ] + [--topic ] + [--username ] + [--password ] + [--https] + [--cycles ] + [--nothrott] + +Demonstrate use of the ECOMP Vendor Event Listener API. + + -h Display this usage message. + --help + + -f The FQDN or IP address to the RESTful API. + --fqdn + + -n The port number the RESTful API. + --port + + -p The optional path prefix to the RESTful API. + --path + + -t The optional topic part of the RESTful API. + --topic + + -u The optional username for basic authentication of requests. + --username + + -w The optional password for basic authentication of requests. + --password + + -s Use HTTPS rather than HTTP for the transport. + --https + + -c Loop times round the main loop. Default = 1. + --cycles + + -v Generate much chattier logs. + --verbose + + -x Exclude throttling commands from demonstration. + --nothrott + +$ +``` +Assuming that all worked as expected, you are ready to start integrating with +your application. It probably makes sense to make the LD_LIBRARY_PATH change +above permanent by incorporating it into your `.bash_profile` file. + +### Project Documentation {#qs_build_docs} + +The source comes with its own documentation included. The documentation can be +built using the `docs` target in the Makefile. By default this builds HTML +and LaTeX documentation, the latter being used to prepare PDFs. + +To make the documentation: +``` +$ cd bldjobs +$ make docs +Cleaning docs... +Making Doxygen documentation +$ +``` + +There is a make target that is intended to install the documentation on a +"team server" - it will need adaptation for your team's environment - see the +`docs_install` target in the Makefile: + +``` +$ make docs_install +Cleaning docs... +Making Doxygen documentation +Copying docs to team web-server... +Enter passphrase for key '/data/home/.ssh/id_rsa': +annotated.html 100% 8088 7.9KB/s 00:00 +arrowdown.png 100% 246 0.2KB/s 00:00 +arrowright.png 100% 229 0.2KB/s 00:00 + ... +$ +``` + +# Project Integration {#qs_integrate} + +There are two key steps to the integration which have to be undertaken: + + * Initialization/Termination of the library. + * Creation & posting of individual events. + +Additionally, it may be necessary to consider changes to the EVEL library's +source code if assumptions made by the library are either not satisfied or +inconvenient. In particular: + + * If the project already uses libcurl then the global initialization of the + library should be removed from the _EVEL Library_. + * The _EVEL Library_ uses `syslog` for event logging. If the project uses a + different event logging process, then EVEL's event logging macros should be + rewritten appropriately. + +These steps are considered in the [Normal Use](@ref qs_normal_use) and +[EVEL Adaptation](@ref qs_adaptation) sections below. + +## Normal Use {#qs_normal_use} + +The _EVEL Library_ should be integrated with your project at a per-process +level: each process is an independent client of the ECOMP Vendor Event Listener +API. + +### Initialization {#qs_initialize} + +The _EVEL Library_ should be initialized before the process becomes +multi-threaded. This constraint arises from the use of libcurl which imposes +the constraint that initialization occurs before the system is multi-threaded. +This is described in more detail in the libcurl documentation for the +[curl_global_init](https://curl.haxx.se/libcurl/c/curl_global_init.html) +function. + +Initialization stores configuration of the Vendor Event Listener API's details, +such as the FQDN or IP address of the service, so the initializing process must +have either extracted this information from its configuration or have this +information "hard-wired" into the application, so that it is available at the +point the `evel_initialize()` function is called: + +```C + #include "evel.h" + ... + if (evel_initialize(api_fqdn, + api_port, + api_path, + api_topic, + api_secure, + "Alice", + "This isn't very secure!", + EVEL_SOURCE_VIRTUAL_MACHINE, + "EVEL demo client", + verbose_mode)) + { + fprintf(stderr, "Failed to initialize the EVEL library!!!"); + exit(-1); + } + ... +``` +Once initialization has occurred successfully, the application may raise events +and may also use the logging functions such as EVEL_INFO(). + +Initialization is entirely local (there is no interaction with the service) so +it is very unlikely to fail, unless the application environment is seriously +degraded. + +### Event Generation {#qs_generate} + +Generating events is a two stage process: + + 1. Firstly, the _EVEL Library_ is called to allocate an event of the correct + type. + * If this is successful, the caller is given a pointer to the event. + * All mandatory fields on the event are provided to this factory function + and are thereafter immutable. + * The application may add any necessary optional fields to the event, using + the pointer previously returned. + 2. The event is sent to the JSON API using the evel_post_event() function. + * At this point, the application relinquishes all responsibility for the + event: + * It will be posted to the JSON API, if possible. + * Whether or not the posting is successful, the memory used will be + freed. + +In practice this looks like: + +```C + #include "evel.h" + ... + + /***************************************************************************/ + /* Create a new Fault object, setting mandatory fields as we do so... */ + /***************************************************************************/ + fault = evel_new_fault("My alarm condition", + "It broke very badly", + EVEL_PRIORITY_NORMAL, + EVEL_SEVERITY_MAJOR); + if (fault != NULL) + { + /*************************************************************************/ + /* We have a Fault object - add some optional fields to it... */ + /*************************************************************************/ + evel_fault_type_set(fault, "Bad things happen..."); + evel_fault_interface_set(fault, "My Interface Card"); + evel_fault_addl_info_add(fault, "name1", "value1"); + evel_fault_addl_info_add(fault, "name2", "value2"); + + /*************************************************************************/ + /* Finally, post the Fault. In practice this will only ever fail if */ + /* local ring-buffer is full because of event overload. */ + /*************************************************************************/ + evel_rc = evel_post_event((EVENT_HEADER *)fault); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + ... +``` +### Event Types {#qs_event_types} + +The _EVEL Library_ supports the following types of events: + + 1. Faults + + These represent the **fault** domain in the event schema. + + 2. Measurements + + These represent the **measurementsForVfScaling** domain in the event + schema. + + 3. Reports + + This is an experimental type, designed to allow VNFs to report + application-level statistics unencumbered with platform measurements. + The formal AT&T schema has been updated to include this experimental + type as **measurementsForVfReporting**. + + 4. Mobile Flow + + These represent the **mobileFlow** domain in the event schema. + + 5. Other + + These represent the **other** domain in the event schema. + + 6. Service Events + + These represent the **serviceEvents** domain in the event schema. + + 7. Signaling + + These represent the **signaling** domain in the event schema. + + 8. State Change + + These represent the **stateChange** domain in the event schema. + + 9. Syslog + + These represent the **syslog** domain in the event schema. + +### Throttling {#qs_throttling} + +The _EVEL library_ supports the following command types as defined in the JSON API: + + 1. commandType: throttlingSpecification + + This is handled internally by the EVEL library, which stores the provided + throttling specification internally and applies it to all subsequent events. + + 2. commandType: provideThrottlingState + + This is handled internally by the EVEL library, which returns the current + throttling specification for each domain. + + 3. commandType: measurementIntervalChange + + This is handled by the EVEL library, which makes the latest measurement + interval available via the ::evel_get_measurement_interval function. + The application is responsible for checking and adhering to the latest + provided interval. + +### Termination {#qs_termination} + +Termination of the _EVEL Library_ is swift and brutal! Events in the buffer +at the time are "dropped on the floor" rather than waiting for the buffer to +deplete first. + +```C + #include "evel.h" + ... + + /***************************************************************************/ + /* Shutdown the library. */ + /***************************************************************************/ + evel_terminate(); + + ... +``` + +## EVEL Adaptation {#qs_adaptation} + +The _EVEL Library_ is relatively simple and should be easy to adapt into other +project environments. + +### LibcURL Lifecycle + +There are two circumstances where initialization of libcurl may be required: + + 1. If libcurl is used by the project already, and therefore already takes + responsibility of its initialization, then the libcurl initialization and + termination functions should be removed from evel_initialize() and + evel_terminate() respectively. + 2. If the project is unable to satisfy the constraint that libcurl + initialization takes place in a single-threaded environment at the point + that the _EVEL Library_ can be initialized (for example, if MT code is + necessary to read the configuration parameters required for + _EVEL Library_ initialization) then it may be necessary to extract the + libcurl functions and call them separately, earlier in the program's + operation. + +### Event Logging + +The _EVEL Library_ uses `syslog` for logging. If this is inappropriate then +the log_debug() and log_initialize() functions should be rewritten accordingly. + +**Note**: it would be a really bad idea to use the _EVEL Library_ itself for this +logging function. +[Turtles all the way down...](https://en.wikipedia.org/wiki/Turtles_all_the_way_down) + + \ No newline at end of file diff --git a/vnfs/VES/code/evel_library/readme.md b/vnfs/VES/code/evel_library/readme.md new file mode 100644 index 00000000..3cf57083 --- /dev/null +++ b/vnfs/VES/code/evel_library/readme.md @@ -0,0 +1,236 @@ +# EVEL Library Overview {#mainpage} + +# Introduction + +The ECOMP Vendor Event Listener ("EVEL") library encapsulates the use of +AT&T's JSON API to the collector function within the ECOMP infrastructure. + +As such, it provides a reference implementation of the EVEL JSON API which +can either be directly as part of a project or can be used to inform the +independent implementation of an equivalent binding to the API in another +development environment. + +This section provides an overview of the library and how it is integrated +into the target application. If all you want is a set of instructions to +get you started, the @ref quickstart "Quick Start" section is for you. If +you want a more in-depth understanding of the _EVEL Library_ then this section +provides an overview and then you can read the detailed API documentation for +each function. The documentation for evel.h is a good starting point, since +that defines the public API of the _EVEL Library_. + +# Library Structure + +The API is designed to be used on multi-process platforms where each process +may be multi-threaded. Each process using this library will create an +independent HTTP client (using libcURL). Each process will have a single +thread running the HTTP client but that thread receives work on a +ring-buffer from however may threads are required to implement the function. + +**Note**: libcurl imposes a constraint that it is initialized before +the process starts multi-threaded operation. + +# Typical Usage + +The library is designed to be very straightforward to use and lightweight to +integrate into projects. The only serious external dependency is on libcURL. + +The supplied Makefile produces a single library **libevel.so** or +**libevel.a** which your application needs to be linked against. + +Each process within the application which wants to generate events needs to +call ::evel_initialize at the start of day (observing the above warning +about not being MT safe at this stage.) The initialization specifies the +details of where the API is located. Management of configuration is the +responsibility of the client. + +Once initialized, and now MT-safe, there are factory functions to produce +new events: +- Faults - ::evel_new_fault +- Measurements - ::evel_new_measurement +- Report - ::evel_new_report +- State Change - ::evel_new_state_change +- Syslog - ::evel_new_syslog +- Other - ::evel_new_other +- Mobile Flow - ::evel_new_mobile_flow + +There is also a factory function ::evel_new_mobile_gtp_flow_metrics to create +the parameter gtp_per_flow_metrics, which is then configured and passed to the +::evel_new_mobile_flow factory function. + +The event structures are initialized with mandatory fields at the point of +creation and optional fields may be added thereafter. Once set, values in +the structures are immutable. + +Once the event is prepared, it may be posted, using ::evel_post_event, at +which point the calling thread relinquishes all responsibility for the +event. It will be freed once successfully or unsuccessfully posted to the +API. If, for any reason, you change your mind and don't want to post a +created event, it must be destroyed with ::evel_free_event. + +Finally, at the end of day, the library can be terminated cleanly by calling +::evel_terminate. + +## Example Code + +The following fragment illustrates the above usage: + +```C + + if (evel_initialize(api_fqdn, + api_port, + api_path, + api_topic, + api_secure, + "Alice", + "This isn't very secure!", + EVEL_SOURCE_VIRTUAL_MACHINE, + "EVEL demo client", + verbose_mode)) + { + fprintf(stderr, "Failed to initialize the EVEL library!!!"); + exit(-1); + } + + ... + + fault = evel_new_fault("My alarm condition", + "It broke very badly", + EVEL_PRIORITY_NORMAL, + EVEL_SEVERITY_MAJOR); + if (fault != NULL) + { + evel_fault_type_set(fault, "Bad things happen..."); + evel_fault_interface_set(fault, "My Interface Card"); + evel_fault_addl_info_add(fault, "name1", "value1"); + evel_fault_addl_info_add(fault, "name2", "value2"); + evel_rc = evel_post_event((EVENT_HEADER *)fault); + if (evel_rc != EVEL_SUCCESS) + { + EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string()); + } + } + +``` + +The public API to the library is defined in evel.h. The internal APIs +within library are defined in separate headers (e.g. +evel_internal.h), but these should not need to be included by the code +using the library. + +# Example Application + +A simple command-line application to generate events is provided as part of +the source package (the above code fragment is taken from that application). + +The following illustrates its operation to a co-located "test-collector": +``` +$ ./evel_demo --fqdn 127.0.0.1 --port 30000 --path vendor_event_listener --topic example_vnf --verbose +./evel_demo built Feb 26 2016 18:14:48 +* About to connect() to 169.254.169.254 port 80 (#0) +* Trying 169.254.169.254... * Timeout +* connect() timed out! +* Closing connection #0 +* About to connect() to 127.0.0.1 port 30000 (#0) +* Trying 127.0.0.1... * connected +* Connected to 127.0.0.1 (127.0.0.1) port 30000 (#0) +* Server auth using Basic with user 'Alice' +> POST /vendor_event_listener/eventListener/v1/example_vnf HTTP/1.1 +Authorization: Basic QWxpY2U6VGhpcyBpc24ndCB2ZXJ5IHNlY3VyZSE= +User-Agent: libcurl-agent/1.0 +Host: 127.0.0.1:30000 +Accept: */* +Content-type: application/json +Content-Length: 510 + +* HTTP 1.0, assume close after body +< HTTP/1.0 204 No Content +< Date: Fri, 04 Mar 2016 15:37:22 GMT +< Server: WSGIServer/0.1 Python/2.6.6 +< +* Closing connection #0 +* About to connect() to 127.0.0.1 port 30000 (#0) +* Trying 127.0.0.1... * connected +* Connected to 127.0.0.1 (127.0.0.1) port 30000 (#0) +* Server auth using Basic with user 'Alice' +> POST /vendor_event_listener/eventListener/v1/example_vnf HTTP/1.1 +Authorization: Basic QWxpY2U6VGhpcyBpc24ndCB2ZXJ5IHNlY3VyZSE= +User-Agent: libcurl-agent/1.0 +Host: 127.0.0.1:30000 +Accept: */* +Content-type: application/json +Content-Length: 865 + +* HTTP 1.0, assume close after body +< HTTP/1.0 204 No Content +< Date: Fri, 04 Mar 2016 15:37:22 GMT +< Server: WSGIServer/0.1 Python/2.6.6 +< +* Closing connection #0 +* About to connect() to 127.0.0.1 port 30000 (#0) +* Trying 127.0.0.1... * connected +* Connected to 127.0.0.1 (127.0.0.1) port 30000 (#0) +* Server auth using Basic with user 'Alice' +> POST /vendor_event_listener/eventListener/v1/example_vnf HTTP/1.1 +Authorization: Basic QWxpY2U6VGhpcyBpc24ndCB2ZXJ5IHNlY3VyZSE= +User-Agent: libcurl-agent/1.0 +Host: 127.0.0.1:30000 +Accept: */* +Content-type: application/json +Content-Length: 2325 + +* HTTP 1.0, assume close after body +< HTTP/1.0 204 No Content +< Date: Fri, 04 Mar 2016 15:37:22 GMT +< Server: WSGIServer/0.1 Python/2.6.6 +< +* Closing connection #0 +^C + +Interrupted - quitting! +$ +``` + +# Restrictions and Limitations + +## Constraint Validation + +The _EVEL Library_ has been designed to be production-safe code with the +emphasis at this stage being in correctness of operation rather than +raw performance. + +The API tries to check as much information as possible to avoid misuse and +will **assert()** if constraints are not satisfied. This is likely to lead +to the rapid discovery of coding errors by programmers, but does mean that +the application can fail abruptly if the library is misused in any way. + +## Performance + +The default Makefile avoids aggressive optimizations so that any core-files +are easy to interpret. Production code should use greater optimization +levels. + +As described above, the HTTP client is single threaded and will run all +transactions synchronously. As transactions are serialized, a client that +generates a lot of events will be paced by the round-trip time. + +It would be a straightforward enhancement to use the multi-thread API into +libcurl and use a pool of client threads to run transactions in parallel if +this ever became a bottleneck. + +## Logging + +The initialization of the library includes the log verbosity. The verbose +operation makes the library very chatty so syslog may get rather clogged +with detailed diagnostics. It is possible to configure syslog to put these +events into a separate file. A trivial syslog.conf file would be: + +``` + +# Log all user messages so debug information is captured. + +user.* /var/log/debug +``` + +If verbose logging is enabled, the cURL library will generate information +about the HTTP operations on **stdout**. + diff --git a/vnfs/VES/code/evel_library/ring_buffer.c b/vnfs/VES/code/evel_library/ring_buffer.c new file mode 100644 index 00000000..3795ed36 --- /dev/null +++ b/vnfs/VES/code/evel_library/ring_buffer.c @@ -0,0 +1,206 @@ +/**************************************************************************//** + * @file + * A ring buffer with multi-threaded synchronization. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include +#include + +#include "ring_buffer.h" +#include "evel.h" + +/**************************************************************************//** + * Ring buffer initialization. + * + * Initialize the buffer supplied to the specified size. + * + * @param buffer Pointer to the ring-buffer to be initialized. + * @param size How many elements to be stored in the ring-buffer. + * + * @returns Nothing +******************************************************************************/ +void ring_buffer_initialize(ring_buffer * buffer, int size) +{ + int pthread_rc = 0; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(buffer != NULL); + assert(size > 0); + + /***************************************************************************/ + /* Initialize the synchronization objects. */ + /***************************************************************************/ + pthread_rc = pthread_mutex_init(&buffer->ring_mutex, NULL); + assert(pthread_rc == 0); + pthread_rc = pthread_cond_init(&buffer->ring_cv, NULL); + assert(pthread_rc == 0); + + /***************************************************************************/ + /* Allocate the ring buffer itself. */ + /***************************************************************************/ + buffer->ring = malloc(size * sizeof(void *)); + assert(buffer->ring != NULL); + + /***************************************************************************/ + /* Initialize the ring as empty. */ + /***************************************************************************/ + buffer->next_write = 0; + buffer->next_read = 0; + buffer->size = size; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Read an element from a ring_buffer. + * + * Reads an element from the ring_buffer, advancing the next-read position. + * Operation is synchronized and therefore MT-safe. Blocks if no data is + * available. + * + * @param buffer Pointer to the ring-buffer to be read. + * + * @returns Pointer to the element read from the buffer. +******************************************************************************/ +void * ring_buffer_read(ring_buffer * buffer) +{ + void *msg = NULL; + EVEL_DEBUG("RBR: Ring buffer read"); + + pthread_mutex_lock(&buffer->ring_mutex); + while (1) + { + EVEL_DEBUG("RBR: got lock. NR=%d NW=%d", + buffer->next_read, + buffer->next_write); + if(buffer->next_read != buffer->next_write) + { + EVEL_DEBUG("RBR: buffer has item available"); + msg = (buffer->ring)[buffer->next_read]; + buffer->ring[buffer->next_read] = NULL; + buffer->next_read = (buffer->next_read + 1) % buffer->size; + EVEL_DEBUG("RBR: next read location is %d", buffer->next_read); + pthread_mutex_unlock(&buffer->ring_mutex); + break; + } + else + { + EVEL_DEBUG("RBR: Waiting for condition variable"); + pthread_cond_wait(&buffer->ring_cv, &buffer->ring_mutex); + EVEL_DEBUG("RBR: Condition variable wait completed"); + } + } + EVEL_DEBUG("RBR: Ring buffer read returning data at %lp", msg); + return msg; +} + +/**************************************************************************//** + * Write an element into a ring_buffer. + * + * Writes an element into the ring_buffer, advancing the next-write position. + * Operation is synchronized and therefore MT-safe. Fails if the buffer is + * full without blocking. + * + * @param buffer Pointer to the ring-buffer to be written. + * @param msg Pointer to data to be stored in the ring_buffer. + * + * @returns Number of items written. + * @retval 1 The data was written successfully. + * @retval 0 The ring_buffer was full so no data written. +******************************************************************************/ +int ring_buffer_write(ring_buffer * buffer, void * msg) +{ + int item_count = 0; + int items_written = 0; + EVEL_DEBUG("RBW: Ring Buffer Write message at %lp", msg); + + pthread_mutex_lock(&buffer->ring_mutex); + EVEL_DEBUG("RBW: got lock. NR=%d NW=%d SZ=%d", + buffer->next_read, + buffer->next_write, + buffer->size); + + item_count = (buffer->next_write - buffer->next_read) % buffer->size; + if (item_count < 0) + { + item_count += buffer->size; + } + if (item_count < buffer->size - 1) + { + EVEL_DEBUG("RBW: %d items in buffer", item_count); + buffer->ring[buffer->next_write] = msg; + buffer->next_write = (buffer->next_write + 1) % buffer->size; + EVEL_DEBUG("RBW: next write location is %d", buffer->next_write); + items_written = 1; + } + else + { + EVEL_ERROR("RBW: ring buffer full - unable to write event"); + } + + pthread_mutex_unlock(&buffer->ring_mutex); + EVEL_DEBUG("RBW: released lock"); + pthread_cond_signal(&buffer->ring_cv); + + return items_written; +} + +/**************************************************************************//** + * Tests whether there is data in the ring_buffer. + * + * Tests whether there is currently data in the ring_buffer without blocking. + * + * @param buffer Pointer to the ring-buffer to be tested. + * + * @returns Whether there is data in the ring_buffer. + * @retval 0 There isn't any data in the ring_buffer. + * @retval 1 There is data in the ring_buffer. +******************************************************************************/ +int ring_buffer_is_empty(ring_buffer * buffer) +{ + int is_empty = 0; + EVEL_DEBUG("RBE: Ring empty check"); + + pthread_mutex_lock(&buffer->ring_mutex); + is_empty = (buffer->next_read == buffer->next_write); + pthread_mutex_unlock(&buffer->ring_mutex); + + EVEL_DEBUG("RBE: Ring state= %d", is_empty); + return is_empty; +} + diff --git a/vnfs/VES/code/evel_library/ring_buffer.h b/vnfs/VES/code/evel_library/ring_buffer.h new file mode 100644 index 00000000..c6870508 --- /dev/null +++ b/vnfs/VES/code/evel_library/ring_buffer.h @@ -0,0 +1,109 @@ +#ifndef RING_BUFFER_INCLUDED +#define RING_BUFFER_INCLUDED + +/**************************************************************************//** + * @file + * A ring buffer. + * + * License + * ------- + * + * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: This product includes + * software developed by the AT&T. + * 4. Neither the name of AT&T nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include + +/**************************************************************************//** + * Ring buffer structure. + *****************************************************************************/ +typedef struct ring_buffer +{ + int size; + int next_write; + int next_read; + void ** ring; + pthread_cond_t ring_cv; + pthread_mutex_t ring_mutex; +} ring_buffer; + +/**************************************************************************//** + * Ring buffer initialization. + * + * Initialize the buffer supplied to the specified size. + * + * @param buffer Pointer to the ring-buffer to be initialized. + * @param size How many elements to be stored in the ring-buffer. + * + * @returns Nothing +******************************************************************************/ +void ring_buffer_initialize(ring_buffer * buffer, int size); + +/**************************************************************************//** + * Read an element from a ring_buffer. + * + * Reads an element from the ring_buffer, advancing the next-read position. + * Operation is synchronized and therefore MT-safe. Blocks if no data is + * available. + * + * @param buffer Pointer to the ring-buffer to be read. + * + * @returns Pointer to the element read from the buffer. +******************************************************************************/ +void * ring_buffer_read(ring_buffer * buffer); + +/**************************************************************************//** + * Write an element into a ring_buffer. + * + * Writes an element into the ring_buffer, advancing the next-write position. + * Operation is synchronized and therefore MT-safe. Fails if the buffer is + * full without blocking. + * + * @param buffer Pointer to the ring-buffer to be written. + * @param msg Pointer to data to be stored in the ring_buffer. + * + * @returns Number of items written. + * @retval 1 The data was written successfully. + * @retval 0 The ring_buffer was full so no data written. +******************************************************************************/ +int ring_buffer_write(ring_buffer * buffer, void * msg); + +/**************************************************************************//** + * Tests whether there is data in the ring_buffer. + * + * Tests whether there is currently data in the ring_buffer without blocking. + * + * @param buffer Pointer to the ring-buffer to be tested. + * + * @returns Whether there is data in the ring_buffer. + * @retval 0 There isn't any data in the ring_buffer. + * @retval 1 There is data in the ring_buffer. +******************************************************************************/ +int ring_buffer_is_empty(ring_buffer * buffer); + +#endif -- cgit 1.2.3-korg