diff options
Diffstat (limited to 'veslibrary/ves_clibrary/evel/evel-library')
44 files changed, 28909 insertions, 0 deletions
diff --git a/veslibrary/ves_clibrary/evel/evel-library/LICENSE.TXT b/veslibrary/ves_clibrary/evel/evel-library/LICENSE.TXT new file mode 100644 index 0000000..ae12da2 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/LICENSE.TXT @@ -0,0 +1,22 @@ +/* + * ============LICENSE_START========================================== + * =================================================================== + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * + * ECOMP and OpenECOMP are trademarks + * and service marks of AT&T Intellectual Property. + * + */ diff --git a/veslibrary/ves_clibrary/evel/evel-library/bldjobs/Makefile b/veslibrary/ves_clibrary/evel/evel-library/bldjobs/Makefile new file mode 100644 index 0000000..5a3a111 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/bldjobs/Makefile @@ -0,0 +1,289 @@ +#*************************************************************************//** +#* +#* Copyright © 2017 AT&T Intellectual Property. All rights reserved. +#* +#* Licensed under the Apache License, Version 2.0 (the "License"); +#* you may not use this file except in compliance with the License. +#* You may obtain a copy of the License at +#* http://www.apache.org/licenses/LICENSE-2.0 +#* +#* Unless required by applicable law or agreed to in writing, software +#* distributed under the License is distributed on an "AS IS" BASIS, +#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#* See the License for the specific language governing permissions and +#* limitations under the License. +#* +#****************************************************************************/ + +#****************************************************************************** +# The ECOMP Vendor Event Listener (EVEL) API client library Makefile. +# +# Make the various targets associated with housekeeping functions as part of +# Event Reporting library. +# +# NOTE: because Makefiles assign special meaning to the TAB character you +# will need to set tabstops to 2 characters for the layout to look OK. +#****************************************************************************/ + +ARCH=$(shell getconf LONG_BIT) +CODE_ROOT=$(CURDIR)/.. +EVELLIB_ROOT=$(CODE_ROOT)/code/evel_library +EVELUNIT_ROOT=$(CODE_ROOT)/code/evel_unit +LIBS_DIR=$(CODE_ROOT)/libs/x86_$(ARCH) +OUTPUT_DIR=$(CODE_ROOT)/output/x86_$(ARCH) +DOCS_ROOT=$(CODE_ROOT)/docs +CC=gcc +SCP=scp +SSH=ssh +JAVA=java +DOXYGEN=doxygen +PLANTUML=/usr/local/bin/plantuml.jar +PLANTFLAGS=-tsvg + +#****************************************************************************** +# Standard compiler flags. * +#****************************************************************************** +CPPFLAGS=-I $(EVELLIB_ROOT) +CFLAGS=-Wall -Wextra -m$(ARCH) -g -fPIC +LIBCFLAGS=-Wall -Wextra -m$(ARCH) -g -shared -fPIC + +#****************************************************************************** +# The testbed is a VM instance where we can install the EVEL example under * +# CentOS. * +#****************************************************************************** +VNF_TESTBED_CENTOS=172.18.152.180 +VNF_TESTBED_CENTOS_USER=centos +TESTBED_CENTOS_DOWNLOAD_PATH=/home/centos/download/evel_lib +TESTBED_CENTOS_INSTALL_PATH=/home/centos/evel + +#****************************************************************************** +# The testbed is a VM instance where we can install the EVEL example under * +# Ubuntu. * +#****************************************************************************** +VNF_TESTBED_UBUNTU=172.18.152.179 +VNF_TESTBED_UBUNTU_USER=ubuntu +TESTBED_UBUNTU_DOWNLOAD_PATH=/home/ubuntu/Downloads/evel_lib +TESTBED_UBUNTU_INSTALL_PATH=/home/ubuntu/evel + +#****************************************************************************** +# The test-collector is where we can send events to be consumed and checked * +# during tests. * +#****************************************************************************** +VNF_COLLECTOR_HOST=172.18.152.185 +VNF_COLLECTOR_PORT=30000 + +#****************************************************************************** +# A documentation server used by the team where we can install documentation. * +#****************************************************************************** +TEAM_DOCS_SERVER=covlx8 +DOCS_SERVER_PATH=/var/www/html/evel + +#****************************************************************************** +# Implicit rule to make dependency files. Recipe copied from Gnu docs at: * +# https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html * +#****************************************************************************** +%.d: %.c + @echo Making dependency file $(notdir $@) for $(notdir $<) + @set -e; rm -f $@; \ + $(CC) -MM -MT $(<:.c=.o) $(CPPFLAGS) $< > $@.$$$$; \ + sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +#****************************************************************************** +# Implicit rule to make object files. * +#****************************************************************************** +%.o: %.c + @echo Making $(notdir $@) from $(notdir $<) + @$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + +#****************************************************************************** +# Implicit rule to make diagram files using PlantUML. * +#****************************************************************************** +%.svg : %.plantuml + @echo Making $(notdir $@) + $(JAVA) -jar $(PLANTUML) $(PLANTFLAGS) $< + +all: api_library \ + +clean: api_library_clean \ + evel_unit_clean \ + +install: api_library + @echo Copying $(LIBS_DIR)/libevel.so + sudo cp $(LIBS_DIR)/libevel.so /usr/lib + sudo ldconfig -n -v /usr/lib + +test: evel_test_centos evel_test_ubuntu + +docs: docs_clean doxygen_docs + + +#****************************************************************************** +# Build the EVEL libraries. * +#****************************************************************************** +API_SOURCES=$(EVELLIB_ROOT)/evel.c \ + $(EVELLIB_ROOT)/metadata.c \ + $(EVELLIB_ROOT)/ring_buffer.c \ + $(EVELLIB_ROOT)/double_list.c \ + $(EVELLIB_ROOT)/hashtable.c \ + $(EVELLIB_ROOT)/evel_event.c \ + $(EVELLIB_ROOT)/evel_fault.c \ + $(EVELLIB_ROOT)/evel_mobile_flow.c \ + $(EVELLIB_ROOT)/evel_option.c \ + $(EVELLIB_ROOT)/evel_jsonobject.c \ + $(EVELLIB_ROOT)/evel_other.c \ + $(EVELLIB_ROOT)/evel_json_buffer.c \ + $(EVELLIB_ROOT)/evel_reporting_measurement.c \ + $(EVELLIB_ROOT)/evel_heartbeat_fields.c \ + $(EVELLIB_ROOT)/evel_sipsignaling.c \ + $(EVELLIB_ROOT)/evel_scaling_measurement.c \ + $(EVELLIB_ROOT)/evel_state_change.c \ + $(EVELLIB_ROOT)/evel_strings.c \ + $(EVELLIB_ROOT)/evel_syslog.c \ + $(EVELLIB_ROOT)/evel_throttle.c \ + $(EVELLIB_ROOT)/evel_internal_event.c \ + $(EVELLIB_ROOT)/evel_event_mgr.c \ + $(EVELLIB_ROOT)/evel_threshold_cross.c \ + $(EVELLIB_ROOT)/evel_voicequality.c \ + $(EVELLIB_ROOT)/evel_logging.c \ + $(EVELLIB_ROOT)/jsmn.c +API_OBJECTS=$(API_SOURCES:.c=.o) +-include $(API_SOURCES:.c=.d) + +api_library: $(LIBS_DIR)/libevel.so \ + $(LIBS_DIR)/libevel.a + +$(LIBS_DIR)/libevel.a: $(API_OBJECTS) + @echo Linking API Static Library + @$(CC) $(LIBCFLAGS) -o $@ $+ + +$(LIBS_DIR)/libevel.so: $(API_OBJECTS) + @echo Linking API Shared Library + @$(CC) $(LIBCFLAGS) -L $(QLIBCLIBSDIR) -lqlibc -o $@ $+ + +api_library_clean: + @echo Cleaning API Library + @$(RM) $(LIBS_DIR)/libevel.so + @$(RM) $(API_OBJECTS) + @$(RM) $(EVELLIB_ROOT)/*.d + +#****************************************************************************** +# Build the EVEL library unit test. * +#****************************************************************************** +UNIT_SOURCES=$(EVELUNIT_ROOT)/evel_unit.c +UNIT_OBJECTS=$(UNIT_SOURCES:.c=.o) +-include $(UNIT_SOURCES:.c=.d) + +evel_unit: api_library \ + $(OUTPUT_DIR)/evel_unit + +$(OUTPUT_DIR)/evel_unit: $(UNIT_OBJECTS) + @echo Linking EVEL unit test + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ \ + -L $(LIBS_DIR) \ + $(UNIT_OBJECTS) \ + -level \ + -lpthread \ + -lcurl + +evel_unit_clean: + @echo Cleaning EVEL unit test + @$(RM) $(OUTPUT_DIR)/evel_unit + @$(RM) $(API_OBJECTS) + @$(RM) $(UNIT_OBJECTS) + @$(RM) $(EVELLIB_ROOT)/*.d + @$(RM) $(EVELUNIT_ROOT)/*.d + +#****************************************************************************** +# Copy the EVEL demo onto the CentOS testbed as a package and build it. * +#****************************************************************************** +evel_install_centos: delivery + @echo Installing EVEL library on CentOS testbed... + @$(SSH) $(VNF_TESTBED_CENTOS_USER)@$(VNF_TESTBED_CENTOS) \ + rm -rf $(TESTBED_CENTOS_DOWNLOAD_PATH) \; \ + mkdir -p $(TESTBED_CENTOS_DOWNLOAD_PATH) \; \ + mkdir -p $(TESTBED_CENTOS_INSTALL_PATH) + @$(SCP) -r $(CODE_ROOT)/output/evel-library-package.tgz \ + $(VNF_TESTBED_CENTOS_USER)@$(VNF_TESTBED_CENTOS):$(TESTBED_CENTOS_DOWNLOAD_PATH) + @$(SSH) $(VNF_TESTBED_CENTOS_USER)@$(VNF_TESTBED_CENTOS) \ + tar zx --directory $(TESTBED_CENTOS_INSTALL_PATH) \ + --file $(TESTBED_CENTOS_DOWNLOAD_PATH)/evel-library-package.tgz + @echo Making EVEL library on testbed... + @$(SSH) $(VNF_TESTBED_CENTOS_USER)@$(VNF_TESTBED_CENTOS) \ + cd $(TESTBED_CENTOS_INSTALL_PATH)/bldjobs \; \ + make clean all + +#****************************************************************************** +# Copy the EVEL demo onto the Ubuntu testbed as a package and build it. * +#****************************************************************************** +evel_install_ubuntu: delivery + @echo Installing EVEL library on Ubuntu testbed... + @$(SSH) $(VNF_TESTBED_UBUNTU_USER)@$(VNF_TESTBED_UBUNTU) \ + rm -rf $(TESTBED_UBUNTU_DOWNLOAD_PATH) \; \ + mkdir -p $(TESTBED_UBUNTU_DOWNLOAD_PATH) \; \ + mkdir -p $(TESTBED_UBUNTU_INSTALL_PATH) + @$(SCP) -r $(CODE_ROOT)/output/evel-library-package.tgz \ + $(VNF_TESTBED_UBUNTU_USER)@$(VNF_TESTBED_UBUNTU):$(TESTBED_UBUNTU_DOWNLOAD_PATH) + @$(SSH) $(VNF_TESTBED_UBUNTU_USER)@$(VNF_TESTBED_UBUNTU) \ + tar zx --directory $(TESTBED_UBUNTU_INSTALL_PATH) \ + --file $(TESTBED_UBUNTU_DOWNLOAD_PATH)/evel-library-package.tgz + @echo Making EVEL library on testbed... + @$(SSH) $(VNF_TESTBED_UBUNTU_USER)@$(VNF_TESTBED_UBUNTU) \ + cd $(TESTBED_UBUNTU_INSTALL_PATH)/bldjobs \; \ + make clean all + +#****************************************************************************** +# Make sure that the Centos platform is up to date and then run the software * +# against a test collector. Validating correct operation is not presently * +# automated. * +#****************************************************************************** +evel_test_centos: evel_install_centos + @echo Testing EVEL Demo application on CentOS... + @$(SSH) $(VNF_TESTBED_CENTOS_USER)@$(VNF_TESTBED_CENTOS) \ + source .bash_profile \; \ + $(TESTBED_CENTOS_INSTALL_PATH)/output/x86_$(ARCH)/evel_demo \ + --fqdn $(VNF_COLLECTOR_HOST) \ + --port $(VNF_COLLECTOR_PORT) \ + --verbose + +#****************************************************************************** +# Make sure that the Ubuntu platform is up to date and then run the software * +# against a test collector. Validating correct operation is not presently * +# automated. * +#****************************************************************************** +evel_test_ubuntu: evel_install_ubuntu + @echo Testing EVEL Demo application on Ubuntu... + @$(SSH) $(VNF_TESTBED_UBUNTU_USER)@$(VNF_TESTBED_UBUNTU) \ + source .profile \; \ + $(TESTBED_UBUNTU_INSTALL_PATH)/output/x86_$(ARCH)/evel_demo \ + --fqdn $(VNF_COLLECTOR_HOST) \ + --port $(VNF_COLLECTOR_PORT) \ + --verbose + +#****************************************************************************** +# Making a clean delivery has some very specific dependencies which are order * +# dependent, so we recursively make a series of targets to do a clean build * +# of all of the required deliverables and then finally zipping up. * +#****************************************************************************** +delivery: + @$(MAKE) -s delivery_baseline + @$(MAKE) -s package + +delivery_baseline: docs + +#****************************************************************************** +# Package the software for delivery. * +#****************************************************************************** +package: api_library_clean \ + evel_unit_clean + @echo Packaging the software for delivery + @cd $(CODE_ROOT) && tar cfz output/evel-library-package.tgz bldjobs \ + code \ + docs \ + libs/x86_64/README \ + output/x86_64/README \ + readme.md + +package_clean: + @echo Clean delivery packages + @$(RM) $(OUTPUTDIR)/*.tgz diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/double_list.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/double_list.c new file mode 100644 index 0000000..6ce8a80 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/double_list.c @@ -0,0 +1,182 @@ + +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @file + * A simple double-linked list. + * + * @note No thread protection so you will need to use appropriate + * synchronization if use spans multiple threads. + * + ****************************************************************************/ + +#include <assert.h> +#include <malloc.h> + +#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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/double_list.h b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/double_list.h new file mode 100644 index 0000000..5cf7e1a --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/double_list.h @@ -0,0 +1,57 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @file + * A simple double-linked list. + * + * @note No thread protection so you will need to use appropriate + * synchronization if use spans multiple threads. + * + ****************************************************************************/ + +#ifndef DOUBLE_LIST_INCLUDED +#define DOUBLE_LIST_INCLUDED + +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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel.c new file mode 100644 index 0000000..20b386d --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel.c @@ -0,0 +1,396 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @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. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <sys/time.h> +#include <curl/curl.h> + +#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_HEARTBEAT_FIELD: + EVEL_DEBUG("Event is a Heartbeat Field Event at %lp", evt_ptr); + evel_free_hrtbt_field((EVENT_HEARTBEAT_FIELD *)evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_HEARTBEAT_FIELD)); + free(evt_ptr); + break; + + case EVEL_DOMAIN_SIPSIGNALING: + 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; + + case EVEL_DOMAIN_VOICE_QUALITY: + EVEL_DEBUG("Event is an VoiceQuality at %lp", evt_ptr); + evel_free_voice_quality((EVENT_VOICE_QUALITY *)evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_VOICE_QUALITY)); + free(evt_ptr); + break; + + case EVEL_DOMAIN_THRESHOLD_CROSS: + EVEL_DEBUG("Event is a Threshold crossing at %lp", evt_ptr); + evel_free_threshold_cross((EVENT_THRESHOLD_CROSS *)evt_ptr); + memset(evt_ptr, 0, sizeof(EVENT_THRESHOLD_CROSS)); + free(evt_ptr); + break; + + default: + EVEL_ERROR("Unexpected event domain (%d)", evt_ptr->event_domain); + assert(0); + } + } + EVEL_EXIT(); +} diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel.h b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel.h new file mode 100644 index 0000000..0ae1713 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel.h @@ -0,0 +1,4494 @@ +#ifndef EVEL_INCLUDED +#define EVEL_INCLUDED +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @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. + *****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdbool.h> +#include <stdio.h> +#include <stdarg.h> +#include <time.h> + +#include "jsmn.h" +#include "double_list.h" +#include "hashtable.h" + +/*****************************************************************************/ +/* Supported API version. */ +/*****************************************************************************/ +#define EVEL_API_MAJOR_VERSION 5 +#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_HEARTBEAT_FIELD,/** A Heartbeat field event. */ + EVEL_DOMAIN_SIPSIGNALING, /** A Signaling event. */ + EVEL_DOMAIN_STATE_CHANGE, /** A State Change event. */ + EVEL_DOMAIN_SYSLOG, /** A Syslog event. */ + EVEL_DOMAIN_OTHER, /** Another event. */ + EVEL_DOMAIN_THRESHOLD_CROSS, /** A Threshold Crossing Event */ + EVEL_DOMAIN_VOICE_QUALITY, /** A Voice Quality 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; + +/**************************************************************************//** + * enrichment fields for internal VES Event Listener service use only, + * not supplied by event sources + *****************************************************************************/ +typedef struct internal_header_fields +{ + void *object; + EVEL_BOOLEAN is_set; +} EVEL_OPTION_INTHEADER_FIELDS; + +/*****************************************************************************/ +/* 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 * event_name; + char * source_name; + 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; + EVEL_OPTION_INTHEADER_FIELDS internal_field; + EVEL_OPTION_STRING nfcnaming_code; + EVEL_OPTION_STRING nfnaming_code; + +} EVENT_HEADER; + +/*****************************************************************************/ +/* Supported Fault version. */ +/*****************************************************************************/ +#define EVEL_FAULT_MAJOR_VERSION 2 +#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 category; + 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; + + +/**************************************************************************//** + * optional field block for fields specific to heartbeat events + *****************************************************************************/ +typedef struct event_heartbeat_fields +{ + /***************************************************************************/ + /* Header and version */ + /***************************************************************************/ + EVENT_HEADER header; + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + double heartbeat_version; + int heartbeat_interval; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + DLIST additional_info; + +} EVENT_HEARTBEAT_FIELD; + +/**************************************************************************//** + * tuple which provides the name of a key along with its value and + * relative order + *****************************************************************************/ +typedef struct internal_key +{ + char *keyname; + EVEL_OPTION_INT keyorder; + EVEL_OPTION_STRING keyvalue; +} EVEL_INTERNAL_KEY; + +/**************************************************************************//** + * meta-information about an instance of a jsonObject along with + * the actual object instance + *****************************************************************************/ +typedef struct json_object_instance +{ + + char *jsonstring; + unsigned long long objinst_epoch_microsec; + DLIST object_keys; /*EVEL_INTERNAL_KEY list */ + +} EVEL_JSON_OBJECT_INSTANCE; +#define MAX_JSON_TOKENS 128 +/**************************************************************************//** + * Create a new json object instance. + * + * @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. + * @param yourjson json string. + * @returns pointer to the newly manufactured ::EVEL_JSON_OBJECT_INSTANCE. + * not used (i.e. posted) it must be released using ::evel_free_jsonobjectinstance. + * @retval NULL Failed to create the json object instance. + *****************************************************************************/ +EVEL_JSON_OBJECT_INSTANCE * evel_new_jsonobjinstance(const char *const yourjson); +/**************************************************************************//** + * Free an json object instance. + * + * Free off the json object instance supplied. + * Will free all the contained allocated memory. + * + *****************************************************************************/ +void evel_free_jsonobjinst(EVEL_JSON_OBJECT_INSTANCE * objinst); + +/**************************************************************************//** + * enrichment fields for internal VES Event Listener service use only, + * not supplied by event sources + *****************************************************************************/ +typedef struct json_object +{ + + char *object_name; + EVEL_OPTION_STRING objectschema; + EVEL_OPTION_STRING objectschemaurl; + EVEL_OPTION_STRING nfsubscribedobjname; + EVEL_OPTION_STRING nfsubscriptionid; + DLIST jsonobjectinstances; /* EVEL_JSON_OBJECT_INSTANCE list */ + +} EVEL_JSON_OBJECT; + +/**************************************************************************//** + * Create a new json object. + * + * @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. + * @param name name of the object. + * @returns pointer to the newly manufactured ::EVEL_JSON_OBJECT. + * not used (i.e. posted) it must be released using ::evel_free_jsonobject. + * @retval NULL Failed to create the json object. + *****************************************************************************/ +EVEL_JSON_OBJECT * evel_new_jsonobject(const char *const name); +/**************************************************************************//** + * Free an json object. + * + * Free off the json object instance supplied. + * Will free all the contained allocated memory. + * + *****************************************************************************/ +void evel_free_jsonobject(EVEL_JSON_OBJECT * jsobj); +/*****************************************************************************/ +/* Supported Measurement version. */ +/*****************************************************************************/ +#define EVEL_MEASUREMENT_MAJOR_VERSION 2 +#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_info; + DLIST additional_measurements; + DLIST additional_objects; + DLIST codec_usage; + EVEL_OPTION_INT concurrent_sessions; + EVEL_OPTION_INT configured_entities; + DLIST cpu_usage; + DLIST disk_usage; + MEASUREMENT_ERRORS * errors; + DLIST feature_usage; + DLIST filesystem_usage; + DLIST latency_distribution; + EVEL_OPTION_DOUBLE mean_request_latency; + DLIST mem_usage; + EVEL_OPTION_INT media_ports_in_use; + EVEL_OPTION_INT request_rate; + EVEL_OPTION_INT vnfc_scaling_metric; + DLIST vnic_usage; + +} EVENT_MEASUREMENT; + +/**************************************************************************//** + * CPU Usage. + * JSON equivalent field: cpuUsage + *****************************************************************************/ +typedef struct measurement_cpu_use { + char * id; + double usage; + EVEL_OPTION_DOUBLE idle; + EVEL_OPTION_DOUBLE intrpt; + EVEL_OPTION_DOUBLE nice; + EVEL_OPTION_DOUBLE softirq; + EVEL_OPTION_DOUBLE steal; + EVEL_OPTION_DOUBLE sys; + EVEL_OPTION_DOUBLE user; + EVEL_OPTION_DOUBLE wait; +} MEASUREMENT_CPU_USE; + + +/**************************************************************************//** + * Disk Usage. + * JSON equivalent field: diskUsage + *****************************************************************************/ +typedef struct measurement_disk_use { + char * id; + EVEL_OPTION_DOUBLE iotimeavg; + EVEL_OPTION_DOUBLE iotimelast; + EVEL_OPTION_DOUBLE iotimemax; + EVEL_OPTION_DOUBLE iotimemin; + EVEL_OPTION_DOUBLE mergereadavg; + EVEL_OPTION_DOUBLE mergereadlast; + EVEL_OPTION_DOUBLE mergereadmax; + EVEL_OPTION_DOUBLE mergereadmin; + EVEL_OPTION_DOUBLE mergewriteavg; + EVEL_OPTION_DOUBLE mergewritelast; + EVEL_OPTION_DOUBLE mergewritemax; + EVEL_OPTION_DOUBLE mergewritemin; + EVEL_OPTION_DOUBLE octetsreadavg; + EVEL_OPTION_DOUBLE octetsreadlast; + EVEL_OPTION_DOUBLE octetsreadmax; + EVEL_OPTION_DOUBLE octetsreadmin; + EVEL_OPTION_DOUBLE octetswriteavg; + EVEL_OPTION_DOUBLE octetswritelast; + EVEL_OPTION_DOUBLE octetswritemax; + EVEL_OPTION_DOUBLE octetswritemin; + EVEL_OPTION_DOUBLE opsreadavg; + EVEL_OPTION_DOUBLE opsreadlast; + EVEL_OPTION_DOUBLE opsreadmax; + EVEL_OPTION_DOUBLE opsreadmin; + EVEL_OPTION_DOUBLE opswriteavg; + EVEL_OPTION_DOUBLE opswritelast; + EVEL_OPTION_DOUBLE opswritemax; + EVEL_OPTION_DOUBLE opswritemin; + EVEL_OPTION_DOUBLE pendingopsavg; + EVEL_OPTION_DOUBLE pendingopslast; + EVEL_OPTION_DOUBLE pendingopsmax; + EVEL_OPTION_DOUBLE pendingopsmin; + EVEL_OPTION_DOUBLE timereadavg; + EVEL_OPTION_DOUBLE timereadlast; + EVEL_OPTION_DOUBLE timereadmax; + EVEL_OPTION_DOUBLE timereadmin; + EVEL_OPTION_DOUBLE timewriteavg; + EVEL_OPTION_DOUBLE timewritelast; + EVEL_OPTION_DOUBLE timewritemax; + EVEL_OPTION_DOUBLE timewritemin; + +} MEASUREMENT_DISK_USE; + +/**************************************************************************//** + * Add an additional Disk 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 Disk utilization. + *****************************************************************************/ +MEASUREMENT_DISK_USE * evel_measurement_new_disk_use_add(EVENT_MEASUREMENT * measurement, char * id); + +/**************************************************************************//** + * Filesystem Usage. + * JSON equivalent field: filesystemUsage + *****************************************************************************/ +typedef struct measurement_fsys_use { + char * filesystem_name; + double block_configured; + double block_iops; + double block_used; + double ephemeral_configured; + double ephemeral_iops; + double ephemeral_used; +} MEASUREMENT_FSYS_USE; + +/**************************************************************************//** + * Memory Usage. + * JSON equivalent field: memoryUsage + *****************************************************************************/ +typedef struct measurement_mem_use { + char * id; + char * vmid; + double membuffsz; + EVEL_OPTION_DOUBLE memcache; + EVEL_OPTION_DOUBLE memconfig; + EVEL_OPTION_DOUBLE memfree; + EVEL_OPTION_DOUBLE slabrecl; + EVEL_OPTION_DOUBLE slabunrecl; + EVEL_OPTION_DOUBLE memused; +} MEASUREMENT_MEM_USE; + +/**************************************************************************//** + * Add an additional Memory 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 Memory identifier. + * @param vmidentifier ASCIIZ string with the VM's identifier. + * @param membuffsz Memory Size. + * + * @return Returns pointer to memory use structure in measurements + *****************************************************************************/ +MEASUREMENT_MEM_USE * evel_measurement_new_mem_use_add(EVENT_MEASUREMENT * measurement, + char * id, char *vmidentifier, double membuffsz); + +/**************************************************************************//** + * Set kilobytes of memory used for cache + * + * @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 mem_use Pointer to the Memory Use. + * @param val double + *****************************************************************************/ +void evel_measurement_mem_use_memcache_set(MEASUREMENT_MEM_USE * const mem_use, + const double val); +/**************************************************************************//** + * Set kilobytes of memory configured in the virtual machine on which the VNFC reporting + * + * @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 mem_use Pointer to the Memory Use. + * @param val double + *****************************************************************************/ +void evel_measurement_mem_use_memconfig_set(MEASUREMENT_MEM_USE * const mem_use, + const double val); +/**************************************************************************//** + * Set kilobytes of physical RAM left unused by the system + * + * @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 mem_use Pointer to the Memory Use. + * @param val double + *****************************************************************************/ +void evel_measurement_mem_use_memfree_set(MEASUREMENT_MEM_USE * const mem_use, + const double val); +/**************************************************************************//** + * Set the part of the slab that can be reclaimed such as caches measured in kilobytes + * + * @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 mem_use Pointer to the Memory Use. + * @param val double + *****************************************************************************/ +void evel_measurement_mem_use_slab_reclaimed_set(MEASUREMENT_MEM_USE * const mem_use, + const double val); +/**************************************************************************//** + * Set the part of the slab that cannot be reclaimed such as caches measured in kilobytes + * + * @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 mem_use Pointer to the Memory Use. + * @param val double + *****************************************************************************/ +void evel_measurement_mem_use_slab_unreclaimable_set(MEASUREMENT_MEM_USE * const mem_use, + const double val); +/**************************************************************************//** + * Set the total memory minus the sum of free, buffered, cached and slab memory in kilobytes + * + * @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 mem_use Pointer to the Memory Use. + * @param val double + *****************************************************************************/ +void evel_measurement_mem_use_usedup_set(MEASUREMENT_MEM_USE * const mem_use, + const double val); +/**************************************************************************//** + * 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_performance { + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + /*Cumulative count of broadcast packets received as read at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_bcast_packets_acc; + /*Count of broadcast packets received within the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_bcast_packets_delta; + /*Cumulative count of discarded packets received as read at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_discarded_packets_acc; + /*Count of discarded packets received within the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_discarded_packets_delta; + /*Cumulative count of error packets received as read at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_error_packets_acc; + /*Count of error packets received within the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_error_packets_delta; + /*Cumulative count of multicast packets received as read at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_mcast_packets_acc; + /*Count of mcast packets received within the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_mcast_packets_delta; + /*Cumulative count of octets received as read at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_octets_acc; + /*Count of octets received within the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_octets_delta; + /*Cumulative count of all packets received as read at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_total_packets_acc; + /*Count of all packets received within the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_total_packets_delta; + /*Cumulative count of unicast packets received as read at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_ucast_packets_acc; + /*Count of unicast packets received within the measurement interval*/ + EVEL_OPTION_DOUBLE recvd_ucast_packets_delta; + /*Cumulative count of transmitted broadcast packets at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE tx_bcast_packets_acc; + /*Count of transmitted broadcast packets within the measurement interval*/ + EVEL_OPTION_DOUBLE tx_bcast_packets_delta; + /*Cumulative count of transmit discarded packets at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE tx_discarded_packets_acc; + /*Count of transmit discarded packets within the measurement interval*/ + EVEL_OPTION_DOUBLE tx_discarded_packets_delta; + /*Cumulative count of transmit error packets at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE tx_error_packets_acc; + /*Count of transmit error packets within the measurement interval*/ + EVEL_OPTION_DOUBLE tx_error_packets_delta; + /*Cumulative count of transmit multicast packets at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE tx_mcast_packets_acc; + /*Count of transmit multicast packets within the measurement interval*/ + EVEL_OPTION_DOUBLE tx_mcast_packets_delta; + /*Cumulative count of transmit octets at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE tx_octets_acc; + /*Count of transmit octets received within the measurement interval*/ + EVEL_OPTION_DOUBLE tx_octets_delta; + /*Cumulative count of all transmit packets at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE tx_total_packets_acc; + /*Count of transmit packets within the measurement interval*/ + EVEL_OPTION_DOUBLE tx_total_packets_delta; + /*Cumulative count of all transmit unicast packets at the end of + the measurement interval*/ + EVEL_OPTION_DOUBLE tx_ucast_packets_acc; + /*Count of transmit unicast packets within the measurement interval*/ + EVEL_OPTION_DOUBLE tx_ucast_packets_delta; + /* Indicates whether vNicPerformance values are likely inaccurate + due to counter overflow or other condtions*/ + char *valuesaresuspect; + char *vnic_id; + +} MEASUREMENT_VNIC_PERFORMANCE; + +/**************************************************************************//** + * 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 2 + +/**************************************************************************//** + * 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; + DLIST additional_info; /* JSON: additionalFields */ + + /***************************************************************************/ + /* 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; + +/*****************************************************************************/ +/* Supported Other field version. */ +/*****************************************************************************/ +#define EVEL_OTHER_EVENT_MAJOR_VERSION 1 +#define EVEL_OTHER_EVENT_MINOR_VERSION 1 + +/**************************************************************************//** + * Other. + * JSON equivalent field: otherFields + *****************************************************************************/ +typedef struct event_other { + EVENT_HEADER header; + int major_version; + int minor_version; + + HASHTABLE_T *namedarrays; /* HASHTABLE_T */ + DLIST jsonobjects; /* DLIST of EVEL_JSON_OBJECT */ + DLIST namedvalues; +} EVENT_OTHER; + +/**************************************************************************//** + * Other Field. + * JSON equivalent field: otherFields + *****************************************************************************/ +typedef struct other_field { + char * name; + char * value; +} OTHER_FIELD; + + +/*****************************************************************************/ +/* Supported Service Events version. */ +/*****************************************************************************/ +#define EVEL_HEARTBEAT_FIELD_MAJOR_VERSION 1 +#define EVEL_HEARTBEAT_FIELD_MINOR_VERSION 1 + + +/*****************************************************************************/ +/* Supported Signaling version. */ +/*****************************************************************************/ +#define EVEL_SIGNALING_MAJOR_VERSION 2 +#define EVEL_SIGNALING_MINOR_VERSION 1 + +/**************************************************************************//** + * Vendor VNF Name fields. + * JSON equivalent field: vendorVnfNameFields + *****************************************************************************/ +typedef struct vendor_vnfname_field { + char * vendorname; + EVEL_OPTION_STRING vfmodule; + EVEL_OPTION_STRING vnfname; +} VENDOR_VNFNAME_FIELD; + +/**************************************************************************//** + * Signaling. + * JSON equivalent field: signalingFields + *****************************************************************************/ +typedef struct event_signaling { + /***************************************************************************/ + /* Header and version */ + /***************************************************************************/ + EVENT_HEADER header; + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + VENDOR_VNFNAME_FIELD vnfname_field; + 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 */ + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + EVEL_OPTION_STRING compressed_sip; /* JSON: compressedSip */ + EVEL_OPTION_STRING summary_sip; /* JSON: summarySip */ + DLIST additional_info; + +} EVENT_SIGNALING; + +/**************************************************************************//** + * Sgnaling Additional Field. + * JSON equivalent field: additionalFields + *****************************************************************************/ +typedef struct signaling_additional_field { + char * name; + char * value; +} SIGNALING_ADDL_FIELD; + +/*****************************************************************************/ +/* Supported State Change version. */ +/*****************************************************************************/ +#define EVEL_STATE_CHANGE_MAJOR_VERSION 1 +#define EVEL_STATE_CHANGE_MINOR_VERSION 2 + +/**************************************************************************//** + * 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; + double version; + + /***************************************************************************/ + /* 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 2 + +/**************************************************************************//** + * 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 */ + /***************************************************************************/ + EVEL_OPTION_STRING additional_filters; + EVEL_OPTION_STRING event_source_host; + EVEL_OPTION_INT syslog_facility; + EVEL_OPTION_INT syslog_priority; + EVEL_OPTION_STRING syslog_proc; + EVEL_OPTION_INT syslog_proc_id; + EVEL_OPTION_STRING syslog_s_data; + EVEL_OPTION_STRING syslog_sdid; + EVEL_OPTION_STRING syslog_severity; + double syslog_fver; + EVEL_OPTION_INT syslog_ver; + +} EVENT_SYSLOG; + +/**************************************************************************//** + * 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); + +/**************************************************************************//** + * Initialize an event instance id. + * + * @param vfield Pointer to the event vnfname field 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_vendor_field(VENDOR_VNFNAME_FIELD * const vfield, + const char * const vendor_name); + +/**************************************************************************//** + * Set the Vendor module property of the Vendor. + * + * @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 vfield Pointer to the Vendor field. + * @param module_name The module name to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_vendor_field_module_set(VENDOR_VNFNAME_FIELD * const vfield, + const char * const module_name); +/**************************************************************************//** + * Set the Vendor module property of the Vendor. + * + * @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 vfield Pointer to the Vendor field. + * @param module_name The module name to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_vendor_field_vnfname_set(VENDOR_VNFNAME_FIELD * const vfield, + const char * const vnfname); +/**************************************************************************//** + * Free an event instance id. + * + * @param vfield Pointer to the event vnfname_field being freed. + *****************************************************************************/ +void evel_free_event_vendor_field(VENDOR_VNFNAME_FIELD * const vfield); + +/**************************************************************************//** + * 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); + +/**************************************************************************//** + * Create a new heartbeat event of given name and type. + * + * @note that the heartbeat is just a "naked" commonEventHeader! + * + * @param event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc + * + * @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_nameid(const char* ev_name, const char *ev_id); + + +/**************************************************************************//** + * 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,const char *const eventname); + +/**************************************************************************//** + * 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); + +/**************************************************************************//** + * Set the NFC Naming code property of the event header. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param nfcnamingcode String + *****************************************************************************/ +void evel_nfcnamingcode_set(EVENT_HEADER * const header, + const char * const nfcnam); +/**************************************************************************//** + * Set the NF Naming code property of the event header. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param nfnamingcode String + *****************************************************************************/ +void evel_nfnamingcode_set(EVENT_HEADER * const header, + const char * const nfnam); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* FAULT */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * 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 event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc + * @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. + * @param ev_source_type Source of Alarm event + * @param version fault version + * @param status status of Virtual Function + * @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* ev_name, const char *ev_id, + const char * const condition, + const char * const specific_problem, + EVEL_EVENT_PRIORITIES priority, + EVEL_SEVERITIES severity, + EVEL_SOURCE_TYPES ev_source_type, + EVEL_VF_STATUSES status); + +/**************************************************************************//** + * 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 Fault Category 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 category Category : license, link, routing, security, signaling. + * ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_fault_category_set(EVENT_FAULT * fault, + const char * const category); + +/**************************************************************************//** + * 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 + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc + * + * @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,const char* ev_name, const char *ev_id); + +/**************************************************************************//** + * 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 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. + *****************************************************************************/ +MEASUREMENT_CPU_USE * evel_measurement_new_cpu_use_add(EVENT_MEASUREMENT * measurement, char * id, double usage); + +/**************************************************************************//** + * Set the CPU Idle value in measurement interval + * percentage of CPU time spent in the idle task + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_idle_set(MEASUREMENT_CPU_USE *const cpu_use, + const double val); + +/**************************************************************************//** + * Set the percentage of time spent servicing interrupts + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_interrupt_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val); + +/**************************************************************************//** + * Set the percentage of time spent running user space processes that have been niced + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_nice_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val); + +/**************************************************************************//** + * Set the percentage of time spent handling soft irq interrupts + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_softirq_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val); +/**************************************************************************//** + * Set the percentage of time spent in involuntary wait + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_steal_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val); +/**************************************************************************//** + * Set the percentage of time spent on system tasks running the kernel + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_system_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val); +/**************************************************************************//** + * Set the percentage of time spent running un-niced user space processes + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_usageuser_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val); +/**************************************************************************//** + * Set the percentage of CPU time spent waiting for I/O operations to complete + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_wait_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val); + +/**************************************************************************//** + * 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, + double block_iops, + double ephemeral_configured, + double ephemeral_used, + double 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 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, + int 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_PERFORMANCE 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_PERFORMANCE has immutable + * properties. + * + * @param vnic_id ASCIIZ string with the vNIC's ID. + * @param val_suspect True or false confidence in data. + * + * @returns pointer to the newly manufactured ::MEASUREMENT_VNIC_PERFORMANCE. + * If the structure is not used it must be released using + * ::evel_measurement_free_vnic_performance. + * @retval NULL Failed to create the vNIC Use. + *****************************************************************************/ +MEASUREMENT_VNIC_PERFORMANCE * evel_measurement_new_vnic_performance(char * const vnic_id, char * const val_suspect); + +/**************************************************************************//** + * Free a vNIC Use. + * + * Free off the ::MEASUREMENT_VNIC_PERFORMANCE 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_measurement_free_vnic_performance(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance); + +/**************************************************************************//** + * Set the Accumulated Broadcast Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_bcast_packets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_bcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_bcast_packets_acc); +/**************************************************************************//** + * Set the Delta Broadcast Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_bcast_packets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_bcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_bcast_packets_delta); +/**************************************************************************//** + * Set the Discarded Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_discard_packets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_discard_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_discard_packets_acc); +/**************************************************************************//** + * Set the Delta Discarded Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_discard_packets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_discard_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_discard_packets_delta); +/**************************************************************************//** + * Set the Error Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_error_packets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_error_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_error_packets_acc); +/**************************************************************************//** + * Set the Delta Error Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_error_packets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_error_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_error_packets_delta); +/**************************************************************************//** + * Set the Accumulated Multicast Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_mcast_packets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_mcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_mcast_packets_acc); +/**************************************************************************//** + * Set the Delta Multicast Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_mcast_packets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_mcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_mcast_packets_delta); +/**************************************************************************//** + * Set the Accumulated Octets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_octets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_octets_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_octets_acc); +/**************************************************************************//** + * Set the Delta Octets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_octets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_octets_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_octets_delta); +/**************************************************************************//** + * Set the Accumulated Total Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_total_packets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_total_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_total_packets_acc); +/**************************************************************************//** + * Set the Delta Total Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_total_packets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_total_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_total_packets_delta); +/**************************************************************************//** + * Set the Accumulated Unicast Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_ucast_packets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_ucast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_ucast_packets_acc); +/**************************************************************************//** + * Set the Delta Unicast packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_ucast_packets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_ucast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_ucast_packets_delta); +/**************************************************************************//** + * Set the Transmitted Broadcast Packets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_bcast_packets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_bcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_bcast_packets_acc); +/**************************************************************************//** + * Set the Delta Broadcast packets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_bcast_packets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_bcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_bcast_packets_delta); +/**************************************************************************//** + * Set the Transmitted Discarded Packets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_discarded_packets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_discarded_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_discarded_packets_acc); +/**************************************************************************//** + * Set the Delta Discarded packets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_discarded_packets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_discarded_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_discarded_packets_delta); +/**************************************************************************//** + * Set the Transmitted Errored Packets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_error_packets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_error_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_error_packets_acc); +/**************************************************************************//** + * Set the Delta Errored packets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_error_packets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_error_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_error_packets_delta); +/**************************************************************************//** + * Set the Transmitted Multicast Packets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_mcast_packets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_mcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_mcast_packets_acc); +/**************************************************************************//** + * Set the Delta Multicast packets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_mcast_packets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_mcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_mcast_packets_delta); +/**************************************************************************//** + * Set the Transmitted Octets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_octets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_octets_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_octets_acc); +/**************************************************************************//** + * Set the Delta Octets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_octets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_octets_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_octets_delta); +/**************************************************************************//** + * Set the Transmitted Total Packets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_total_packets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_total_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_total_packets_acc); +/**************************************************************************//** + * Set the Delta Total Packets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_total_packets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_total_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_total_packets_delta); +/**************************************************************************//** + * Set the Transmitted Unicast Packets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_ucast_packets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_ucast_packets_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_ucast_packets_acc); +/**************************************************************************//** + * Set the Delta Octets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_ucast_packets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_ucast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_ucast_packets_delta); + +/**************************************************************************//** + * Add an additional vNIC Use to the specified Measurement event. + * + * @param measurement Pointer to the measurement. + * @param vnic_performance Pointer to the vNIC Use to add. + *****************************************************************************/ +void evel_meas_vnic_performance_add(EVENT_MEASUREMENT * const measurement, + MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance); + +/**************************************************************************//** + * 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 valset true or false confidence level + * @param recvd_bcast_packets_acc Recieved broadcast packets + * @param recvd_bcast_packets_delta Received delta broadcast packets + * @param recvd_discarded_packets_acc Recieved discarded packets + * @param recvd_discarded_packets_delta Received discarded delta packets + * @param recvd_error_packets_acc Received error packets + * @param recvd_error_packets_delta, Received delta error packets + * @param recvd_mcast_packets_acc Received multicast packets + * @param recvd_mcast_packets_delta Received delta multicast packets + * @param recvd_octets_acc Received octets + * @param recvd_octets_delta Received delta octets + * @param recvd_total_packets_acc Received total packets + * @param recvd_total_packets_delta Received delta total packets + * @param recvd_ucast_packets_acc Received Unicast packets + * @param recvd_ucast_packets_delta Received delta unicast packets + * @param tx_bcast_packets_acc Transmitted broadcast packets + * @param tx_bcast_packets_delta Transmitted delta broadcast packets + * @param tx_discarded_packets_acc Transmitted packets discarded + * @param tx_discarded_packets_delta Transmitted delta discarded packets + * @param tx_error_packets_acc Transmitted error packets + * @param tx_error_packets_delta Transmitted delta error packets + * @param tx_mcast_packets_acc Transmitted multicast packets accumulated + * @param tx_mcast_packets_delta Transmitted delta multicast packets + * @param tx_octets_acc Transmitted octets + * @param tx_octets_delta Transmitted delta octets + * @param tx_total_packets_acc Transmitted total packets + * @param tx_total_packets_delta Transmitted delta total packets + * @param tx_ucast_packets_acc Transmitted Unicast packets + * @param tx_ucast_packets_delta Transmitted delta Unicast packets + *****************************************************************************/ +void evel_measurement_vnic_performance_add(EVENT_MEASUREMENT * const measurement, + char * const vnic_id, + char * valset, + double recvd_bcast_packets_acc, + double recvd_bcast_packets_delta, + double recvd_discarded_packets_acc, + double recvd_discarded_packets_delta, + double recvd_error_packets_acc, + double recvd_error_packets_delta, + double recvd_mcast_packets_acc, + double recvd_mcast_packets_delta, + double recvd_octets_acc, + double recvd_octets_delta, + double recvd_total_packets_acc, + double recvd_total_packets_delta, + double recvd_ucast_packets_acc, + double recvd_ucast_packets_delta, + double tx_bcast_packets_acc, + double tx_bcast_packets_delta, + double tx_discarded_packets_acc, + double tx_discarded_packets_delta, + double tx_error_packets_acc, + double tx_error_packets_delta, + double tx_mcast_packets_acc, + double tx_mcast_packets_delta, + double tx_octets_acc, + double tx_octets_delta, + double tx_total_packets_acc, + double tx_total_packets_delta, + double tx_ucast_packets_acc, + double tx_ucast_packets_delta); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* 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 + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc + * + * @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,const char* ev_name, const char *ev_id); + +/**************************************************************************//** + * 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 event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc + * @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* ev_name, const char *ev_id, + 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); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* 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 event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc + * @param vendor_name The vendor id to encode in the event vnf field. + * @param module The module to encode in the event. + * @param vnfname The Virtual network function to encode in the event. + * @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* ev_name, const char *ev_id, + const char * const vendor_name, + const char * const correlator, + const char * const local_ip_address, + const char * const local_port, + const char * const remote_ip_address, + const char * const remote_port); + +/**************************************************************************//** + * 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); + +/**************************************************************************//** + * Add an additional value name/value pair to the SIP signaling. + * + * 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 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_signaling_addl_info_add(EVENT_SIGNALING * event, char * name, char * value); + +/**************************************************************************//** + * 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 Vendor module 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 modulename The module name to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_vnfmodule_name_set(EVENT_SIGNALING * const event, + const char * const module_name); +/**************************************************************************//** + * Set the Vendor module 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 vnfname The Virtual Network function to be set. ASCIIZ string. + * The caller does not need to preserve the value once + * the function returns. + *****************************************************************************/ +void evel_signaling_vnfname_set(EVENT_SIGNALING * const event, + const char * const vnfname); + +/**************************************************************************//** + * 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 event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc + * @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 char* ev_name, const char *ev_id, + 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_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc + * @param event_source_type + * @param syslog_msg + * @param syslog_tag + * @param version + * + * @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(const char* ev_name, const char *ev_id, + 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); + +/**************************************************************************//** + * Set the Structured SDID 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 sdid The Structured Data to be set. ASCIIZ string. name@number + * Caller does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_sdid_set(EVENT_SYSLOG * syslog, const char * const sdid); + +/**************************************************************************//** + * Set the Structured Severity 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 sdid The Structured Data to be set. ASCIIZ string. + * Caller does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_severity_set(EVENT_SYSLOG * syslog, const char * const severty); + + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* OTHER */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +/**************************************************************************//** + * Create a new other event. + * + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc + * + * @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(const char* ev_name, const char *ev_id); + +/**************************************************************************//** + * 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(); + +/*****************************************************************************/ +/* Supported Report version. */ +/*****************************************************************************/ +#define EVEL_VOICEQ_MAJOR_VERSION 1 +#define EVEL_VOICEQ_MINOR_VERSION 1 + +/**************************************************************************//** + * End of Call Voice Quality Metrices + * JSON equivalent field: endOfCallVqmSummaries + *****************************************************************************/ +typedef struct end_of_call_vqm_summaries { + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + char* adjacencyName; + char* endpointDescription; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + EVEL_OPTION_INT endpointJitter; + EVEL_OPTION_INT endpointRtpOctetsDiscarded; + EVEL_OPTION_INT endpointRtpOctetsReceived; + EVEL_OPTION_INT endpointRtpOctetsSent; + EVEL_OPTION_INT endpointRtpPacketsDiscarded; + EVEL_OPTION_INT endpointRtpPacketsReceived; + EVEL_OPTION_INT endpointRtpPacketsSent; + EVEL_OPTION_INT localJitter; + EVEL_OPTION_INT localRtpOctetsDiscarded; + EVEL_OPTION_INT localRtpOctetsReceived; + EVEL_OPTION_INT localRtpOctetsSent; + EVEL_OPTION_INT localRtpPacketsDiscarded; + EVEL_OPTION_INT localRtpPacketsReceived; + EVEL_OPTION_INT localRtpPacketsSent; + EVEL_OPTION_INT mosCqe; + EVEL_OPTION_INT packetsLost; + EVEL_OPTION_INT packetLossPercent; + EVEL_OPTION_INT rFactor; + EVEL_OPTION_INT roundTripDelay; + +} END_OF_CALL_VOICE_QUALITY_METRICS; + +/**************************************************************************//** +* Voice QUality. +* JSON equivalent field: voiceQualityFields +*****************************************************************************/ + +typedef struct event_voiceQuality { + /***************************************************************************/ + /* Header and version */ + /***************************************************************************/ + EVENT_HEADER header; + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + + char *calleeSideCodec; + char *callerSideCodec; + char *correlator; + char *midCallRtcp; + VENDOR_VNFNAME_FIELD vendorVnfNameFields; + END_OF_CALL_VOICE_QUALITY_METRICS *endOfCallVqmSummaries; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + EVEL_OPTION_STRING phoneNumber; + DLIST additionalInformation; + +} EVENT_VOICE_QUALITY; +/**************************************************************************//** + * Voice Quality Additional Info. + * JSON equivalent field: additionalInformation + *****************************************************************************/ +typedef struct voice_quality_additional_info { + char * name; + char * value; +} VOICE_QUALITY_ADDL_INFO; + +/**************************************************************************//** + * Create a new voice quality event. + * + * @note The mandatory fields on the Voice Quality 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 Voice Quality has immutable properties. + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc + * @param calleeSideCodec Callee codec for the call. + * @param callerSideCodec Caller codec for the call. + * @param correlator Constant across all events on this call. + * @param midCallRtcp Base64 encoding of the binary RTCP data + * (excluding Eth/IP/UDP headers). + * @param vendorVnfNameFields Vendor, VNF and VfModule names. + * @returns pointer to the newly manufactured ::EVENT_VOICE_QUALITY. If the + * event is not used (i.e. posted) it must be released using + ::evel_free_voice_quality. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_VOICE_QUALITY * evel_new_voice_quality(const char* ev_name, const char *ev_id, + const char * const calleeSideCodec, + const char * const callerSideCodec, const char * const correlator, + const char * const midCallRtcp, const char * const vendorVnfNameFields); + +/**************************************************************************//** + * Set the Callee side codec for Call for domain Voice Quality + * + * @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 voiceQuality Pointer to the Voice Quality Event. + * @param calleeCodecForCall The Callee Side Codec to be set. ASCIIZ + * string. The caller does not need to + * preserve the value once the function + * returns. + *****************************************************************************/ +void evel_voice_quality_callee_codec_set(EVENT_VOICE_QUALITY * voiceQuality, + const char * const calleeCodecForCall); + +/**************************************************************************//** + * Set the Caller side codec for Call for domain Voice Quality + * + * @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 voiceQuality Pointer to the Voice Quality Event. + * @param callerCodecForCall The Caller Side Codec to be set. ASCIIZ + * string. The caller does not need to + * preserve the value once the function + * returns. + *****************************************************************************/ +void evel_voice_quality_caller_codec_set(EVENT_VOICE_QUALITY * voiceQuality, + const char * const callerCodecForCall); + +/**************************************************************************//** + * Set the correlator for domain Voice Quality + * + * @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 voiceQuality Pointer to the Voice Quality Event. + * @param correlator The correlator value to be set. ASCIIZ + * string. The caller does not need to + * preserve the value once the function + * returns. + *****************************************************************************/ +void evel_voice_quality_correlator_set(EVENT_VOICE_QUALITY * voiceQuality, + const char * const vCorrelator); + +/**************************************************************************//** + * Set the RTCP Call Data for domain Voice Quality + * + * @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 voiceQuality Pointer to the Voice Quality Event. + * @param rtcpCallData The RTCP Call Data to be set. ASCIIZ + * string. The caller does not need to + * preserve the value once the function + * returns. + *****************************************************************************/ +void evel_voice_quality_rtcp_data_set(EVENT_VOICE_QUALITY * voiceQuality, + const char * const rtcpCallData); + +/**************************************************************************//** + * Set the Vendor VNF Name fields for domain Voice Quality + * + * @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 voiceQuality Pointer to the Voice Quality Event. + * @param nameFields The Vendor, VNF and VfModule names to be set. + * ASCIIZ string. The caller does not need to + * preserve the value once the function + * returns. + *****************************************************************************/ +void evel_voice_quality_name_fields_set(EVENT_VOICE_QUALITY * voiceQuality, + const char * const nameFields); + +/**************************************************************************//** + * Add an End of Call Voice Quality Metrices + + * The adjacencyName and endpointDescription is null delimited ASCII string. + * The library takes a copy so the caller does not have to preserve values + * after the function returns. + * + * @param voiceQuality Pointer to the measurement. + * @param adjacencyName Adjacency name + * @param endpointDescription Enumeration: ‘Caller’, ‘Callee’. + * @param endpointJitter Endpoint jitter + * @param endpointRtpOctetsDiscarded Endpoint RTP octets discarded. + * @param endpointRtpOctetsReceived Endpoint RTP octets received. + * @param endpointRtpOctetsSent Endpoint RTP octets sent + * @param endpointRtpPacketsDiscarded Endpoint RTP packets discarded. + * @param endpointRtpPacketsReceived Endpoint RTP packets received. + * @param endpointRtpPacketsSent Endpoint RTP packets sent. + * @param localJitter Local jitter. + * @param localRtpOctetsDiscarded Local RTP octets discarded. + * @param localRtpOctetsReceived Local RTP octets received. + * @param localRtpOctetsSent Local RTP octets sent. + * @param localRtpPacketsDiscarded Local RTP packets discarded. + * @param localRtpPacketsReceived Local RTP packets received. + * @param localRtpPacketsSent Local RTP packets sent. + * @param mosCqe Decimal range from 1 to 5 + * (1 decimal place) + * @param packetsLost No Packets lost + * @param packetLossPercent Calculated percentage packet loss + * @param rFactor rFactor from 0 to 100 + * @param roundTripDelay Round trip delay in milliseconds + *****************************************************************************/ +void evel_voice_quality_end_metrics_add(EVENT_VOICE_QUALITY * voiceQuality, + const char * adjacencyName, EVEL_SERVICE_ENDPOINT_DESC endpointDescription, + int endpointJitter, + int endpointRtpOctetsDiscarded, + int endpointRtpOctetsReceived, + int endpointRtpOctetsSent, + int endpointRtpPacketsDiscarded, + int endpointRtpPacketsReceived, + int endpointRtpPacketsSent, + int localJitter, + int localRtpOctetsDiscarded, + int localRtpOctetsReceived, + int localRtpOctetsSent, + int localRtpPacketsDiscarded, + int localRtpPacketsReceived, + int localRtpPacketsSent, + int mosCqe, + int packetsLost, + int packetLossPercent, + int rFactor, + int roundTripDelay); + +/**************************************************************************//** + * Free a Voice Quality. + * + * Free off the Voce Quality supplied. Will free all the contained allocated + * memory. + * + * @note It does not free the Voice Quality itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_voice_quality(EVENT_VOICE_QUALITY * voiceQuality); + +/**************************************************************************//** + * Add an additional value name/value pair to the Voice Quality. + * + * 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_voice_quality_addl_info_add(EVENT_VOICE_QUALITY * voiceQuality, char * name, char * value); + + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* THRESHOLD CROSSING ALERT */ +/* */ +/*****************************************************************************/ +/*****************************************************************************/ + +typedef enum evel_event_action { + EVEL_EVENT_ACTION_CLEAR, + EVEL_EVENT_ACTION_CONTINUE, + EVEL_EVENT_ACTION_SET, + EVEL_MAX_EVENT_ACTION +}EVEL_EVENT_ACTION; + +typedef enum evel_alert_type { + EVEL_CARD_ANOMALY, + EVEL_ELEMENT_ANOMALY, + EVEL_INTERFACE_ANOMALY, + EVEL_SERVICE_ANOMALY, + EVEL_MAX_ANOMALY +}EVEL_ALERT_TYPE; + + +typedef struct perf_counter { + char * criticality; + char * name; + char * thresholdCrossed; + char * value; +}PERF_COUNTER; + + +/*****************************************************************************/ +/* Supported Threshold Crossing version. */ +/*****************************************************************************/ +#define EVEL_THRESHOLD_CROSS_MAJOR_VERSION 1 +#define EVEL_THRESHOLD_CROSS_MINOR_VERSION 1 + +/**************************************************************************//** + * Threshold Crossing. + * JSON equivalent field: Threshold Cross Fields + *****************************************************************************/ +typedef struct event_threshold_cross { + /***************************************************************************/ + /* Header and version */ + /***************************************************************************/ + EVENT_HEADER header; + int major_version; + int minor_version; + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + PERF_COUNTER additionalParameters; + EVEL_EVENT_ACTION alertAction; + char * alertDescription; + EVEL_ALERT_TYPE alertType; + unsigned long long collectionTimestamp; + EVEL_SEVERITIES eventSeverity; + unsigned long long eventStartTimestamp; + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + DLIST additional_info; + EVEL_OPTION_STRING alertValue; + DLIST alertidList; + EVEL_OPTION_STRING dataCollector; + EVEL_OPTION_STRING elementType; + EVEL_OPTION_STRING interfaceName; + EVEL_OPTION_STRING networkService; + EVEL_OPTION_STRING possibleRootCause; + +} EVENT_THRESHOLD_CROSS; + + +/**************************************************************************//** + * Create a new Threshold Crossing Alert event. + * + * @note The mandatory fields on the TCA 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 + * TCA has immutable properties. + * + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc + * @param char* tcriticality Performance Counter Criticality MAJ MIN, + * @param char* tname Performance Counter Threshold name + * @param char* tthresholdCrossed Counter Threshold crossed value + * @param char* tvalue Counter actual value + * @param EVEL_EVENT_ACTION talertAction Alert set continue or clear + * @param char* talertDescription + * @param EVEL_ALERT_TYPE talertType Kind of anamoly + * @param unsigned long long tcollectionTimestamp time at which alert was collected + * @param EVEL_SEVERITIES teventSeverity Severity of Alert + * @param unsigned long long teventStartTimestamp Time when this alert started + * + * @returns pointer to the newly manufactured ::EVENT_THRESHOLD_CROSS. If the + * event is not used it must be released using + * ::evel_free_threshold_cross + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_THRESHOLD_CROSS * evel_new_threshold_cross( + const char* ev_name, const char *ev_id, + char * tcriticality, + char * tname, + char * tthresholdCrossed, + char * tvalue, + EVEL_EVENT_ACTION talertAction, + char * talertDescription, + EVEL_ALERT_TYPE talertType, + unsigned long long tcollectionTimestamp, + EVEL_SEVERITIES teventSeverity, + unsigned long long teventStartTimestamp); + +/**************************************************************************//** + * Free a Threshold cross event. + * + * Free off the Threshold crossing event supplied. Will free all the contained allocated + * memory. + * + * @note It does not free the Threshold Cross itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_threshold_cross(EVENT_THRESHOLD_CROSS * const tcp); + +/**************************************************************************//** + * Set the Event Type property of the Threshold Cross. + * + * @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 tcp Pointer to the ::EVENT_THRESHOLD_CROSS. + * @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_threshold_cross_type_set(EVENT_THRESHOLD_CROSS * const tcp, char * type); + +/**************************************************************************//** + * Add an optional additional alertid value to Alert. + * + * @param alertid Adds Alert ID + *****************************************************************************/ +void evel_threshold_cross_alertid_add(EVENT_THRESHOLD_CROSS * const event,char * alertid); + + /**************************************************************************//** + * Set the TCA probable Root cause. + * + * @param sheader Possible root cause to Threshold + *****************************************************************************/ + void evel_threshold_cross_possible_rootcause_set(EVENT_THRESHOLD_CROSS * const event, char * sheader); + /**************************************************************************//** + * Set the TCA networking cause. + * + * @param sheader Possible networking service value to Threshold + *****************************************************************************/ + void evel_threshold_cross_networkservice_set(EVENT_THRESHOLD_CROSS * const event, char * sheader); + /**************************************************************************//** + * Set the TCA Interface name. + * + * @param sheader Interface name to threshold + *****************************************************************************/ + void evel_threshold_cross_interfacename_set(EVENT_THRESHOLD_CROSS * const event,char * sheader); + /**************************************************************************//** + * Set the TCA Data element type. + * + * @param sheader element type of Threshold + *****************************************************************************/ + void evel_threshold_cross_data_elementtype_set(EVENT_THRESHOLD_CROSS * const event,char * sheader); + /**************************************************************************//** + * Set the TCA Data collector value. + * + * @param sheader Data collector value + *****************************************************************************/ + void evel_threshold_cross_data_collector_set(EVENT_THRESHOLD_CROSS * const event,char * sheader); + /**************************************************************************//** + * Set the TCA alert value. + * + * @param sheader Possible alert value + *****************************************************************************/ + void evel_threshold_cross_alertvalue_set(EVENT_THRESHOLD_CROSS * const event,char * sheader); + +/**************************************************************************//** + * Add an additional field name/value pair to the THRESHOLD CROSS event. + * + * 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_THRESHOLD_CROSS. + * @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_threshold_cross_addl_info_add(EVENT_THRESHOLD_CROSS * const tcp, + const char * const name, + const char * const value); + +/*****************************************************************************/ +/*****************************************************************************/ +/* */ +/* 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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_event.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_event.c new file mode 100644 index 0000000..ced29b2 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_event.c @@ -0,0 +1,755 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to Event Headers - since + * Heartbeats only contain the Event Header, the Heartbeat factory function is + * here too. + *****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <sys/time.h> + +#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 of given name and type. + * + * @note that the heartbeat is just a "naked" commonEventHeader! + * + * @param event_name Unique Event Name: in format + * {DomainAbbreviation}_{AsdcModel or ApplicationPlatform}_{DescriptionOfInfoBeingConveyed} + * @param event_id Uniquely identify event for correlation and analysis + * + * @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_nameid(const char* ev_name, const char *ev_id) +{ + EVENT_HEADER * heartbeat = NULL; + EVEL_ENTER(); + + assert(ev_name != NULL); + assert(ev_id != NULL); + + /***************************************************************************/ + /* 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_nameid(heartbeat,ev_name,ev_id); + +exit_label: + EVEL_EXIT(); + return heartbeat; +} + +/**************************************************************************//** + * 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,"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,const char *const eventname) +{ + 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); + if( eventname == NULL ) + header->event_name = strdup(functional_role); + else + header->event_name = strdup(eventname); + 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_init_option_string(&header->nfcnaming_code); + evel_init_option_string(&header->nfnaming_code); + evel_force_option_string(&header->reporting_entity_id, openstack_vm_uuid()); + evel_force_option_string(&header->source_id, openstack_vm_uuid()); + evel_init_option_intheader(&header->internal_field); + + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Initialize a newly created event header. + * + * @param header Pointer to the header being initialized. + *****************************************************************************/ +void evel_init_header_nameid(EVENT_HEADER * const header,const char *const eventname, const char *eventid) +{ + struct timeval tv; + + EVEL_ENTER(); + + assert(header != NULL); + assert(eventname != NULL); + assert(eventid != 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; + header->event_id = strdup(eventid); + header->event_name = strdup(eventname); + 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_init_option_string(&header->nfcnaming_code); + evel_init_option_string(&header->nfnaming_code); + evel_force_option_string(&header->reporting_entity_id, openstack_vm_uuid()); + evel_force_option_string(&header->source_id, openstack_vm_uuid()); + evel_init_option_intheader(&header->internal_field); + + 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 NFC Naming code property of the event header. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param nfcnamingcode String + *****************************************************************************/ +void evel_nfcnamingcode_set(EVENT_HEADER * const header, + const char * const nfcnam) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and assign the new value. */ + /***************************************************************************/ + assert(header != NULL); + assert(nfcnam != NULL); + evel_set_option_string(&header->nfcnaming_code, nfcnam, "NFC Naming Code"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the NF Naming code property of the event header. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param nfnamingcode String + *****************************************************************************/ +void evel_nfnamingcode_set(EVENT_HEADER * const header, + const char * const nfnam) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and assign the new value. */ + /***************************************************************************/ + assert(header != NULL); + assert(nfnam != NULL); + evel_set_option_string(&header->nfnaming_code, nfnam, "NF Naming Code"); + + 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, "eventName", event->event_name); + 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_enc_kv_opt_string(jbuf, "nfcNamingCode", &event->nfcnaming_code); + evel_enc_kv_opt_string(jbuf, "nfNamingCode", &event->nfnaming_code); + + 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->event_name); + evel_free_option_string(&event->reporting_entity_id); + free(event->reporting_entity_name); + evel_free_option_string(&event->source_id); + evel_free_option_string(&event->nfcnaming_code); + evel_free_option_string(&event->nfnaming_code); + evel_free_option_intheader(&event->internal_field); + 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_HEARTBEAT_FIELD: + evel_json_encode_hrtbt_field(jbuf, (EVENT_HEARTBEAT_FIELD *)event); + break; + + case EVEL_DOMAIN_SIPSIGNALING: + 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_VOICE_QUALITY: + evel_json_encode_voice_quality(jbuf, (EVENT_VOICE_QUALITY *)event); + break; + + case EVEL_DOMAIN_THRESHOLD_CROSS: + evel_json_encode_threshold_cross(jbuf, (EVENT_THRESHOLD_CROSS *)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 vfield Pointer to the event vnfname field 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_vendor_field(VENDOR_VNFNAME_FIELD * const vfield, + const char * const vendor_name) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(vfield != NULL); + assert(vendor_name != NULL); + + /***************************************************************************/ + /* Store the mandatory parts. */ + /***************************************************************************/ + vfield->vendorname = strdup(vendor_name); + evel_init_option_string(&vfield->vfmodule); + evel_init_option_string(&vfield->vnfname); + + /***************************************************************************/ + /* Initialize the optional parts. */ + /***************************************************************************/ + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Vendor module property of the Vendor. + * + * @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 vfield Pointer to the Vendor field. + * @param module_name The module name to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_vendor_field_module_set(VENDOR_VNFNAME_FIELD * const vfield, + const char * const module_name) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(vfield != NULL); + assert(module_name != NULL); + + evel_set_option_string(&vfield->vfmodule, module_name, "Module name set"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Vendor module property of the Vendor. + * + * @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 vfield Pointer to the Vendor field. + * @param module_name The module name to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_vendor_field_vnfname_set(VENDOR_VNFNAME_FIELD * const vfield, + const char * const vnfname) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(vfield != NULL); + assert(vnfname != NULL); + + evel_set_option_string(&vfield->vnfname, vnfname, "Virtual Network Function name set"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free an event instance id. + * + * @param vfield Pointer to the event vnfname_field being freed. + *****************************************************************************/ +void evel_free_event_vendor_field(VENDOR_VNFNAME_FIELD * const vfield) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(vfield->vendorname != NULL); + + /***************************************************************************/ + /* Free everything. */ + /***************************************************************************/ + evel_free_option_string(&vfield->vfmodule); + evel_free_option_string(&vfield->vnfname); + free(vfield->vendorname); + + 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 vfield Pointer to the ::VENDOR_VNFNAME_FIELD to encode. + *****************************************************************************/ +void evel_json_encode_vendor_field(EVEL_JSON_BUFFER * jbuf, + VENDOR_VNFNAME_FIELD * vfield) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(jbuf->json != NULL); + assert(jbuf->max_size > 0); + assert(vfield != NULL); + assert(vfield->vendorname != NULL); + + evel_json_open_named_object(jbuf, "vendorVnfNameFields"); + + /***************************************************************************/ + /* Mandatory fields. */ + /***************************************************************************/ + evel_enc_kv_string(jbuf, "vendorName", vfield->vendorname); + evel_enc_kv_opt_string(jbuf, "vfModuleName", &vfield->vfmodule); + evel_enc_kv_opt_string(jbuf, "vnfName", &vfield->vnfname); + + /***************************************************************************/ + /* Optional fields. */ + /***************************************************************************/ + + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_event_mgr.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_event_mgr.c new file mode 100644 index 0000000..a96124a --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_event_mgr.c @@ -0,0 +1,1050 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @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. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <pthread.h> + +#include <curl/curl.h> + +#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] = "<NULL>"; + +/**************************************************************************//** + * 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); + + + curl_version_info_data *d = curl_version_info(CURLVERSION_NOW); + /* compare with the 24 bit hex number in 8 bit fields */ + if(d->version_num >= 0x072100) { + /* this is libcurl 7.33.0 or later */ + EVEL_INFO("7.33 or later Curl version %x.",d->version_num); + } + else { + EVEL_INFO("Old Curl version."); + } + /***************************************************************************/ + /* 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,"EVELinternal","EVELid"); + 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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_fault.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_fault.c new file mode 100644 index 0000000..c211f60 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_fault.c @@ -0,0 +1,367 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the Fault. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#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 event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc + * @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. + * @param ev_source_type Source of Alarm event + * @param version fault version + * @param status status of Virtual Function + * @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 * ev_name, + const char * ev_id, + const char * const condition, + const char * const specific_problem, + EVEL_EVENT_PRIORITIES priority, + EVEL_SEVERITIES severity, + EVEL_SOURCE_TYPES ev_source_type, + EVEL_VF_STATUSES status) +{ + 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_nameid(&fault->header,ev_name,ev_id); + 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 = ev_source_type; + fault->vf_status = status; + fault->alarm_condition = strdup(condition); + fault->specific_problem = strdup(specific_problem); + evel_init_option_string(&fault->category); + 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 Fault Category 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 category Category : license, link, routing, security, signaling. + * ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_fault_category_set(EVENT_FAULT * fault, + const char * const category) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(fault != NULL); + assert(fault->header.event_domain == EVEL_DOMAIN_FAULT); + assert(category != NULL); + + evel_set_option_string(&fault->category, + category, + "Fault Category set"); + 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_opt_string(jbuf, "eventCategory", &event->category); + 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); + free(event->specific_problem); + evel_free_option_string(&event->category); + evel_free_option_string(&event->alarm_interface_a); + evel_free_header(&event->header); + + EVEL_EXIT(); +} diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_heartbeat_fields.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_heartbeat_fields.c new file mode 100644 index 0000000..872af1f --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_heartbeat_fields.c @@ -0,0 +1,269 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to Heartbeat fields. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#include "evel.h" +#include "evel_throttle.h" + +/**************************************************************************//** + * Create a new Heartbeat fields event. + * + * @note The mandatory fields on the Heartbeat fields 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 event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc + * @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_HEARTBEAT_FIELD. If the event + * is not used (i.e. posted) it must be released using + * ::evel_free_hrtbt_field. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_HEARTBEAT_FIELD * evel_new_heartbeat_field(int interval,const char* ev_name, const char *ev_id) +{ + EVENT_HEARTBEAT_FIELD * event = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(interval > 0); + + /***************************************************************************/ + /* Allocate the Heartbeat fields event. */ + /***************************************************************************/ + event = malloc(sizeof(EVENT_HEARTBEAT_FIELD)); + if (event == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(event, 0, sizeof(EVENT_HEARTBEAT_FIELD)); + EVEL_DEBUG("New Heartbeat fields event is at %lp", event); + + /***************************************************************************/ + /* Initialize the header & the Heartbeat fields fields. */ + /***************************************************************************/ + evel_init_header_nameid(&event->header,ev_name,ev_id); + event->header.event_domain = EVEL_DOMAIN_HEARTBEAT_FIELD; + event->major_version = EVEL_HEARTBEAT_FIELD_MAJOR_VERSION; + event->minor_version = EVEL_HEARTBEAT_FIELD_MINOR_VERSION; + + event->heartbeat_interval = interval; + dlist_initialize(&event->additional_info); + +exit_label: + + EVEL_EXIT(); + return event; +} + +/**************************************************************************//** + * Add a name/value pair to the Heartbeat fields, 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 Heartbeat fields 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_hrtbt_field_addl_field_add(EVENT_HEARTBEAT_FIELD * 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_HEARTBEAT_FIELD); + 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_info, nv_pair); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Interval property of the Heartbeat fields 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 Heartbeat fields 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_hrtbt_interval_set(EVENT_HEARTBEAT_FIELD * const event, + const int interval) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_set_option_string. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_HEARTBEAT_FIELD); + assert(interval > 0); + + event->heartbeat_interval = interval; + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Encode the Heartbeat fields 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_hrtbt_field(EVEL_JSON_BUFFER * const jbuf, + EVENT_HEARTBEAT_FIELD * 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_HEARTBEAT_FIELD); + + evel_json_encode_header(jbuf, &event->header); + evel_json_open_named_object(jbuf, "heartbeatField"); + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + evel_enc_version(jbuf, "heartbeatFieldsVersion", event->major_version,event->minor_version); + evel_enc_kv_int(jbuf, "heartbeatInterval", event->heartbeat_interval); + + /***************************************************************************/ + /* 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, "additionalFields")) + { + bool added = false; + + dlist_item = dlist_get_first(&event->additional_info); + 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); + } + } + + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free a Heartbeat fields 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_hrtbt_field(EVENT_HEARTBEAT_FIELD * const event) +{ + OTHER_FIELD * nv_pair = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_HEARTBEAT_FIELD); + + /***************************************************************************/ + /* Free all internal strings then the header itself. */ + /***************************************************************************/ + nv_pair = dlist_pop_last(&event->additional_info); + 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_info); + } + evel_free_header(&event->header); + + EVEL_EXIT(); +} diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_internal.h b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_internal.h new file mode 100644 index 0000000..46f71af --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_internal.h @@ -0,0 +1,858 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @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. + * + ****************************************************************************/ + +#ifndef EVEL_INTERNAL_INCLUDED +#define EVEL_INTERNAL_INCLUDED + +#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,const char* ev_name, const char *ev_id); + +/**************************************************************************//** + * 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); + +/*****************************************************************************/ +/* 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 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 Heartbeat fields 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_hrtbt_field(EVEL_JSON_BUFFER * const jbuf, + EVENT_HEARTBEAT_FIELD * 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); + + +/**************************************************************************//** + * Initialize an ::EVEL_OPTION_INTHEADER_FIELDS to a not-set state. + * + * @param option Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS. + *****************************************************************************/ +void evel_init_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option); +/**************************************************************************//** + * Force the value of an ::EVEL_OPTION_INTHEADER_FIELDS. + * + * @param option Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS. + * @param value The value to set. + *****************************************************************************/ +void evel_force_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option, + const void* value); +/**************************************************************************//** + * Set the value of an ::EVEL_OPTION_INTHEADER_FIELDS. + * + * @param option Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS. + * @param value The value to set. + * @param description Description to be used in logging. + *****************************************************************************/ +void evel_set_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option, + const void * value, + const char * const description); +/**************************************************************************//** + * Free the underlying resources of an ::EVEL_OPTION_INTHEADER_FIELDS. + * + * @param option Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS. + *****************************************************************************/ +void evel_free_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option); + +#endif diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_internal_event.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_internal_event.c new file mode 100644 index 0000000..cb56c88 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_internal_event.c @@ -0,0 +1,113 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @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. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#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. + * @param event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc + * @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,const char* ev_name, const char *ev_id) +{ + 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_nameid(&event->header,ev_name,ev_id); + 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(); +} diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_json_buffer.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_json_buffer.c new file mode 100644 index 0000000..b6026e2 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_json_buffer.c @@ -0,0 +1,870 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @file + * Source module relating to internal EVEL_JSON_BUFFER manipulation functions. + * + ****************************************************************************/ + +#include <assert.h> +#include <string.h> + +#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 json object 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 json string to encode. + *****************************************************************************/ +void evel_enc_kv_object(EVEL_JSON_BUFFER * jbuf, + const char * const key, + const char * 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\": %s", + 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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_jsonobject.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_jsonobject.c new file mode 100644 index 0000000..caf1a1e --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_jsonobject.c @@ -0,0 +1,446 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to json_object. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#include "jsmn.h" +#include "evel.h" +#include "evel_internal.h" + +/**************************************************************************//** + * Create a new json object. + * + * @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. + * @param name name of the object. + * @returns pointer to the newly manufactured ::EVEL_JSON_OBJECT. + * not used (i.e. posted) it must be released using ::evel_free_jsonobject. + * @retval NULL Failed to create the json object. + *****************************************************************************/ +EVEL_JSON_OBJECT * evel_new_jsonobject(const char *const name) +{ + EVEL_JSON_OBJECT *jobj = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(name != NULL); + + /***************************************************************************/ + /* Allocate the json object. */ + /***************************************************************************/ + jobj = malloc(sizeof(EVEL_JSON_OBJECT)); + if (jobj == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(jobj, 0, sizeof(EVEL_JSON_OBJECT)); + EVEL_DEBUG("New json object is at %lp", jobj); + + /***************************************************************************/ + /* Initialize the fields. Optional string values are */ + /* uninitialized (NULL). */ + /***************************************************************************/ + jobj->object_name = strdup(name); + evel_init_option_string(&jobj->objectschema); + evel_init_option_string(&jobj->objectschemaurl); + evel_init_option_string(&jobj->nfsubscribedobjname); + evel_init_option_string(&jobj->nfsubscriptionid); + dlist_initialize(&jobj->jsonobjectinstances); + +exit_label: + EVEL_EXIT(); + return jobj; +} + + +/**************************************************************************//** + * Create a new json object instance. + * + * @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. + * @param yourjson json string. + * @returns pointer to the newly manufactured ::EVEL_JSON_OBJECT_INSTANCE. + * not used (i.e. posted) it must be released using ::evel_free_jsonobjectinstance. + * @retval NULL Failed to create the json object instance. + *****************************************************************************/ +EVEL_JSON_OBJECT_INSTANCE * evel_new_jsonobjinstance(const char *const yourjson) +{ + EVEL_JSON_OBJECT_INSTANCE *jobjinst = NULL; + jsmntok_t *key; + int resultCode; + jsmn_parser p; + jsmntok_t tokens[MAX_JSON_TOKENS]; // a number >= total number of tokens + int len=0; + + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(yourjson != NULL); + len = strlen(yourjson)+1; + assert(len > 0); + + /***************************************************************************/ + /* Validate JSON for json object + /***************************************************************************/ + jsmn_init(&p); + resultCode = jsmn_parse(&p, yourjson, len, tokens, sizeof(tokens)/sizeof(tokens[0])); + if( resultCode < 0 ){ + log_error_state("Failed to parse json for object"); + goto exit_label; + } + + if (resultCode < 1 || tokens[0].type != JSMN_OBJECT) { + log_error_state("Error json object expected"); + goto exit_label; + } + + /***************************************************************************/ + /* Allocate the json object. */ + /***************************************************************************/ + jobjinst = malloc(sizeof(EVEL_JSON_OBJECT_INSTANCE)); + if (jobjinst == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(jobjinst, 0, sizeof(EVEL_JSON_OBJECT_INSTANCE)); + + /***************************************************************************/ + /* Initialize the fields. Optional key values are */ + /* uninitialized (NULL). */ + /***************************************************************************/ + jobjinst->jsonstring = strdup(yourjson); + dlist_initialize(&jobjinst->object_keys); + +exit_label: + EVEL_EXIT(); + return jobjinst; +} + + +/**************************************************************************//** + * Create a new internal key. + * + * @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. + * @param keyname name of the key. + * @returns pointer to the newly manufactured ::EVEL_INTERNAL_KEY. + * not used (i.e. posted) it must be released using ::evel_free_internal_key. + * @retval NULL Failed to create the internal key. + *****************************************************************************/ +EVEL_INTERNAL_KEY * evel_new_internal_key(char *keyname) +{ + EVEL_INTERNAL_KEY *keyinst = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(keyname != NULL); + + /***************************************************************************/ + /* Allocate the key object. */ + /***************************************************************************/ + keyinst = malloc(sizeof(EVEL_INTERNAL_KEY)); + if (keyinst == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(keyinst, 0, sizeof(EVEL_INTERNAL_KEY)); + keyinst->keyname = strdup(keyname); + + /***************************************************************************/ + /* Optional string values are uninitialized (NULL). */ + /***************************************************************************/ + evel_init_option_int(&keyinst->keyorder); + evel_init_option_string(&keyinst->keyvalue); + +exit_label: + EVEL_EXIT(); + return keyinst; +} + +/**************************************************************************//** + * Set the keyorder of the internal key instance. + * + * @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 int keyorder + *****************************************************************************/ +void evel_internal_key_keyorder_set(EVEL_INTERNAL_KEY * pinst, const int keyorder) +{ + assert (pinst != NULL); + evel_set_option_int(&pinst->keyorder,keyorder,"Key order"); +} + +/**************************************************************************//** + * Set the keyvalue of the internal key instance. + * + * @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 string keyvalue + *****************************************************************************/ +void evel_internal_key_keyvalue_set(EVEL_INTERNAL_KEY * pinst, const char * const keyval) +{ + assert (pinst != NULL); + evel_set_option_string(&pinst->keyvalue,keyval,"Key Value"); +} + +/**************************************************************************//** + * Set the string values of json object + * + * @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 string object schema + *****************************************************************************/ +void evel_jsonobject_objectschema_set(EVEL_JSON_OBJECT * pinst, const char * const objectschema) +{ + assert (pinst != NULL); + evel_set_option_string(&pinst->objectschema,objectschema,"Object Schema"); +} + +/**************************************************************************//** + * Set the string values of json object + * + * @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 string object schema url + *****************************************************************************/ +void evel_jsonobject_objectschemaurl_set(EVEL_JSON_OBJECT * pinst, const char * const objectschemaurl) +{ + assert (pinst != NULL); + evel_set_option_string(&pinst->objectschemaurl,objectschemaurl,"Object Schema URL"); +} + +/**************************************************************************//** + * Set the string values of json object + * + * @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 string NF Subscribed object name + *****************************************************************************/ +void evel_jsonobject_nfsubscribedobjname_set(EVEL_JSON_OBJECT * pinst, const char * const nfsubscribedobjname) +{ + assert (pinst != NULL); + evel_set_option_string(&pinst->nfsubscribedobjname,nfsubscribedobjname,"NF Subscribed Object Name"); +} + +/**************************************************************************//** + * Set the string values of json object + * + * @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 string NF Subscription Id + *****************************************************************************/ +void evel_jsonobject_nfsubscriptionid_set(EVEL_JSON_OBJECT * pinst, const char * const nfsubscriptionid) +{ + assert (pinst != NULL); + evel_set_option_string(&pinst->nfsubscriptionid,nfsubscriptionid,"NF Subscription Id"); +} + +/**************************************************************************//** + * Set the Epoch time of the json object instance. + * + * @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 unsigned long long epoch time + *****************************************************************************/ +void evel_epoch_microsec_set(EVEL_JSON_OBJECT_INSTANCE * pinst, const unsigned long long epmicrosec) +{ + assert(epmicrosec != 0 ); + pinst->objinst_epoch_microsec = epmicrosec; +} + +/**************************************************************************//** + * Add a json object instance to jsonObject list. + * + * 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 pobj Pointer to the Other. + * @param jinst Pointer to HashTable + *****************************************************************************/ +void evel_jsonobject_add_jsoninstance(EVEL_JSON_OBJECT * pobj, EVEL_JSON_OBJECT_INSTANCE *jinst) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(pobj != NULL); + assert(jinst != NULL); + + EVEL_DEBUG("Adding json object instance"); + + dlist_push_last(&pobj->jsonobjectinstances, jinst); + + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Add a json object to jsonObject list. + * + * 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 jsonobj Pointer to json object + *****************************************************************************/ +void evel_jsonobjinst_add_objectkey(EVEL_JSON_OBJECT_INSTANCE * jsoninst, EVEL_INTERNAL_KEY *keyp) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jsoninst != NULL); + assert(keyp != NULL); + + EVEL_DEBUG("Adding jsonObject instance"); + + dlist_push_last(&jsoninst->object_keys, keyp); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free an internal key. + * + * Free off the internal key supplied. Will free all the contained allocated memory. + * + *****************************************************************************/ +void evel_free_internal_key(EVEL_INTERNAL_KEY * keyp) +{ + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the public API. */ + /***************************************************************************/ + assert(keyp != NULL); + + free(keyp->keyname); + evel_free_option_string(&keyp->keyvalue); + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Free an json object instance. + * + * Free off the json object instance supplied. + * Will free all the contained allocated memory. + * + *****************************************************************************/ +void evel_free_jsonobjinst(EVEL_JSON_OBJECT_INSTANCE * objinst) +{ + EVEL_INTERNAL_KEY *other_field = NULL; + + EVEL_ENTER(); + assert(objinst != NULL); + assert(objinst->jsonstring != NULL); + + free(objinst->jsonstring); + + /***************************************************************************/ + /* Free all internal internal keys + /***************************************************************************/ + other_field = dlist_pop_last(&objinst->object_keys); + while (other_field != NULL) + { + EVEL_DEBUG("Freeing Object Instance Field (%s)", + other_field->keyname); + evel_free_internal_key(other_field); + other_field = dlist_pop_last(&objinst->object_keys); + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free an json object. + * + * Free off the json object instance supplied. + * Will free all the contained allocated memory. + * + *****************************************************************************/ +void evel_free_jsonobject(EVEL_JSON_OBJECT * jsobj) +{ + EVEL_JSON_OBJECT_INSTANCE *other_field = NULL; + + EVEL_ENTER(); + assert(jsobj != NULL); + + free(jsobj->object_name); + evel_free_option_string(&jsobj->objectschema); + evel_free_option_string(&jsobj->objectschemaurl); + evel_free_option_string(&jsobj->nfsubscribedobjname); + evel_free_option_string(&jsobj->nfsubscriptionid); + + /***************************************************************************/ + /* Free all internal strings then the header itself. */ + /***************************************************************************/ + other_field = dlist_pop_last(&jsobj->jsonobjectinstances); + while (other_field != NULL) + { + EVEL_DEBUG("Freeing Object Instance Field (%s)", + other_field->jsonstring); + evel_free_jsonobjinst(other_field); + other_field = dlist_pop_last(&jsobj->jsonobjectinstances); + } + + EVEL_EXIT(); +} diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_logging.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_logging.c new file mode 100644 index 0000000..5a44f07 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_logging.c @@ -0,0 +1,167 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * Wrapper for event logging built on syslog. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <syslog.h> +#include <stdlib.h> +#include <sys/time.h> + +#include <curl/curl.h> + +#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] = "<NULL>"; + + +/**************************************************************************//** + * 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 + * "<null>" 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); + } +} diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_mobile_flow.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_mobile_flow.c new file mode 100644 index 0000000..5085d6a --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_mobile_flow.c @@ -0,0 +1,2122 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the Mobile Flow. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <time.h> + +#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 event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc + * @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* ev_name, const char *ev_id, + 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_nameid(&mobile_flow->header,ev_name,ev_id); + 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); + dlist_initialize(&mobile_flow->additional_info); + +exit_label: + EVEL_EXIT(); + return mobile_flow; +} + +/**************************************************************************//** + * Add an additional value name/value pair to the Mobile flow. + * + * 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 Mobile flow. + * @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_mobile_flow_addl_field_add(EVENT_MOBILE_FLOW * const event, char * name, char * value) +{ + OTHER_FIELD * nv_pair = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW); + 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_info, nv_pair); + + EVEL_EXIT(); +} + + +/**************************************************************************//** + * 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) +{ + OTHER_FIELD * nv_pair = NULL; + DLIST_ITEM * dlist_item = NULL; + + 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"); + + + /***************************************************************************/ + /* 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_info); + 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); + } + } + + + /***************************************************************************/ + /* 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); + evel_enc_version(jbuf, + "mobileFlowFieldsVersion", + event->major_version, + event->minor_version); + 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) +{ + OTHER_FIELD * nv_pair = 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_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); + + /***************************************************************************/ + /* Free all internal strings then the header itself. */ + /***************************************************************************/ + nv_pair = dlist_pop_last(&event->additional_info); + 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_info); + } + + 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(); +} diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_option.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_option.c new file mode 100644 index 0000000..7d53e8f --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_option.c @@ -0,0 +1,526 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * Source module relating to EVEL_OPTION_ types. + * + ****************************************************************************/ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#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_INTHEADER_FIELDS to a not-set state. + * + * @param option Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS. + *****************************************************************************/ +void evel_init_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + option->object = NULL; + option->is_set = EVEL_FALSE; + EVEL_EXIT(); +} + +/**************************************************************************//** + * Force the value of an ::EVEL_OPTION_INTHEADER_FIELDS. + * + * @param option Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS. + * @param value The value to set. + *****************************************************************************/ +void evel_force_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option, + const void* value) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + option->object = value; + option->is_set = EVEL_TRUE; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the value of an ::EVEL_OPTION_INTHEADER_FIELDS. + * + * @param option Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS. + * @param value The value to set. + * @param description Description to be used in logging. + *****************************************************************************/ +void evel_set_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option, + const void * 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->object); + } + else + { + EVEL_DEBUG("Setting %s to %llu", description, value); + option->object = value; + option->is_set = EVEL_TRUE; + } + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free the underlying resources of an ::EVEL_OPTION_INTHEADER_FIELDS. + * + * @param option Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS. + *****************************************************************************/ +void evel_free_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(option != NULL); + + if (option->is_set) + { + free(option->object); + option->object = NULL; + option->is_set = EVEL_FALSE; + } + + 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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_other.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_other.c new file mode 100644 index 0000000..c7a227b --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_other.c @@ -0,0 +1,492 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to Other. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#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(const char *ev_name, const char *ev_id) +{ + 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_nameid(&other->header,ev_name,ev_id); + other->header.event_domain = EVEL_DOMAIN_OTHER; + other->major_version = EVEL_OTHER_EVENT_MAJOR_VERSION; + other->minor_version = EVEL_OTHER_EVENT_MINOR_VERSION; + + other->namedarrays = NULL; + dlist_initialize(&other->jsonobjects); + dlist_initialize(&other->namedvalues); + +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 json object to jsonObject list. + * + * 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 size size of hashtable + *****************************************************************************/ +void evel_other_field_set_namedarraysize(EVENT_OTHER * other, const int size) +{ + OTHER_FIELD * other_field = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(other != NULL); + assert(other->header.event_domain == EVEL_DOMAIN_OTHER); + assert(other->namedarrays == NULL); + assert(size > 0); + + EVEL_DEBUG("Adding Named array"); + + other->namedarrays = ht_create(size); + + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Add a json object to jsonObject list. + * + * 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 size size of hashtable + *****************************************************************************/ +void evel_other_field_add_namedarray(EVENT_OTHER * other, const char *hashname, char * name, char *value) +{ + OTHER_FIELD * other_field = NULL; + DLIST *list = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(other != NULL); + assert(other->header.event_domain == EVEL_DOMAIN_OTHER); + assert(other->namedarrays != NULL); + + EVEL_DEBUG("Adding values to Named array"); + + 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); + + + list = ht_get(other->namedarrays, hashname); + if( list == NULL ) + { + DLIST * nlist = malloc(sizeof(DLIST)); + dlist_initialize(nlist); + dlist_push_last(nlist, other_field); + ht_set(other->namedarrays, hashname, nlist); + EVEL_DEBUG("Created to new table table"); + } + else + { + dlist_push_last(list, other_field); + EVEL_DEBUG("Adding to existing table"); + } + + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Add a json object to jsonObject list. + * + * 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 jsonobj Pointer to json object + *****************************************************************************/ +void evel_other_field_add_jsonobj(EVENT_OTHER * other, EVEL_JSON_OBJECT *jsonobj) +{ + OTHER_FIELD * other_field = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(other != NULL); + assert(other->header.event_domain == EVEL_DOMAIN_OTHER); + assert(jsonobj != NULL); + + EVEL_DEBUG("Adding jsonObject"); + + dlist_push_last(&other->jsonobjects, jsonobj); + + 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->namedvalues, 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; + EVEL_JSON_OBJECT * jsonobjp = NULL; + DLIST_ITEM * other_field_item = NULL; + EVEL_JSON_OBJECT_INSTANCE * jsonobjinst = NULL; + DLIST_ITEM * jsobj_field_item = NULL; + EVEL_INTERNAL_KEY * keyinst = NULL; + DLIST_ITEM * keyinst_field_item = NULL; + HASHTABLE_T *ht = NULL; + int i; + bool itm_added = false; + DLIST *itm_list = 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_object(jbuf, "otherFields"); + +// iterate through hashtable and print DLIST for each entry + + ht = event->namedarrays; + if( ht != NULL ) + { + if( ht->size > 0) + { + for( i = 0; i < ht->size; i++ ) { + if( ht->table[i] != NULL) + { + itm_added = true; + } + } + if( itm_added == true) + { + + if (evel_json_open_opt_named_list(jbuf, "hashOfNameValuePairArrays")) + { + for( i = 0; i < ht->size; i++ ) { + if( ht->table[i] != NULL) + { + itm_list = ht->table[i]; + + if(evel_json_open_opt_named_list(jbuf, ht->table[i]->key)) + { + other_field_item = dlist_get_first(&itm_list); + while (other_field_item != NULL) + { + other_field = (OTHER_FIELD *) other_field_item->item; + if(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_json_close_list(jbuf); + } + + + } + } + } + + evel_json_checkpoint(jbuf); + if(evel_json_open_opt_named_list(jbuf, "jsonObjects")) + { + bool item_added = false; + other_field_item = dlist_get_first(&event->jsonobjects); + while (other_field_item != NULL) + { + jsonobjp = (EVEL_JSON_OBJECT *) other_field_item->item; + if(jsonobjp != NULL); + { + evel_json_open_object(jbuf); + + if( evel_json_open_opt_named_list(jbuf, "objectInstances")) + { + bool item_added2 = false; + jsobj_field_item = dlist_get_first(&jsonobjp->jsonobjectinstances); + while (jsobj_field_item != NULL) + { + jsonobjinst = (EVEL_JSON_OBJECT_INSTANCE *) jsobj_field_item->item; + if( jsonobjinst != NULL ) + { + evel_json_open_object(jbuf); + evel_enc_kv_object(jbuf, "objectInstance", jsonobjinst->jsonstring); + evel_enc_kv_ull(jbuf, "objectInstanceEpochMicrosec", jsonobjinst->objinst_epoch_microsec); + //evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "objectKeys")) + { + bool item_added3 = false; + + keyinst_field_item = dlist_get_first(&jsonobjinst->object_keys); + while (keyinst_field_item != NULL) + { + keyinst = (EVEL_INTERNAL_KEY *)keyinst_field_item->item; + if(keyinst != NULL) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "keyName", keyinst->keyname); + evel_enc_kv_opt_int(jbuf, "keyOrder", &keyinst->keyorder); + evel_enc_kv_opt_string(jbuf, "keyValue", &keyinst->keyvalue); + evel_json_close_object(jbuf); + item_added3 = false; + } + keyinst_field_item = dlist_get_next(keyinst_field_item); + } + evel_json_close_list(jbuf); + + /*************************************************************************/ + /* If we've not written anything, rewind to before we opened the list. */ + /*************************************************************************/ + //if (!item_added3) + //{ + // evel_json_rewind(jbuf); + //} + } + evel_json_close_object(jbuf); + } + item_added2 = true; + jsobj_field_item = dlist_get_next(jsobj_field_item); + } + evel_json_close_list(jbuf); + if( !item_added2 ) + { + evel_json_rewind(jbuf); + } + } + + evel_enc_kv_string(jbuf, "objectName", jsonobjp->object_name); + evel_enc_kv_opt_string(jbuf, "objectSchema", &jsonobjp->objectschema); + evel_enc_kv_opt_string(jbuf, "objectSchemaUrl", &jsonobjp->objectschemaurl); + evel_enc_kv_opt_string(jbuf, "nfSubscribedObjectName", &jsonobjp->nfsubscribedobjname); + evel_enc_kv_opt_string(jbuf, "nfSubscriptionId", &jsonobjp->nfsubscriptionid); + evel_json_close_object(jbuf); + item_added = true; + } + other_field_item = dlist_get_next(other_field_item); + } + evel_json_close_list(jbuf); + + if (!item_added) + { + evel_json_rewind(jbuf); + } + + } + + if( evel_json_open_opt_named_list(jbuf, "nameValuePairs")) + { + other_field_item = dlist_get_first(&event->namedvalues); + 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_enc_version(jbuf, "otherFieldsVersion", event->major_version,event->minor_version); + + evel_json_close_object(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->namedvalues); + 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->namedvalues); + } + evel_free_header(&event->header); + + EVEL_EXIT(); +} diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_reporting_measurement.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_reporting_measurement.c new file mode 100644 index 0000000..36c34da --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_reporting_measurement.c @@ -0,0 +1,437 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @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. + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#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 + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc + * @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,const char *ev_name, const char *ev_id) +{ + 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_nameid(&report->header,ev_name,ev_id); + 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->minor_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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_scaling_measurement.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_scaling_measurement.c new file mode 100644 index 0000000..b3e73c9 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_scaling_measurement.c @@ -0,0 +1,3716 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the Measurement. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#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 + * @param event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc + * + * @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, const char* ev_name, const char *ev_id) +{ + 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_nameid(&measurement->header,ev_name,ev_id); + measurement->header.event_domain = EVEL_DOMAIN_MEASUREMENT; + measurement->measurement_interval = measurement_interval; + dlist_initialize(&measurement->additional_info); + dlist_initialize(&measurement->additional_measurements); + dlist_initialize(&measurement->additional_objects); + dlist_initialize(&measurement->cpu_usage); + dlist_initialize(&measurement->disk_usage); + dlist_initialize(&measurement->mem_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); + evel_init_option_double(&measurement->mean_request_latency); + evel_init_option_int(&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(); +} + +/**************************************************************************//** + * Add an additional 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 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_measurement_addl_info_add(EVENT_MEASUREMENT * measurement, char * name, char * value) +{ + OTHER_FIELD * addl_info = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(name != NULL); + assert(value != NULL); + + EVEL_DEBUG("Adding name=%s value=%s", name, value); + addl_info = malloc(sizeof(OTHER_FIELD)); + assert(addl_info != NULL); + memset(addl_info, 0, sizeof(OTHER_FIELD)); + addl_info->name = strdup(name); + addl_info->value = strdup(value); + assert(addl_info->name != NULL); + assert(addl_info->value != NULL); + + dlist_push_last(&measurement->additional_info, addl_info); + + 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 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. + *****************************************************************************/ +MEASUREMENT_CPU_USE *evel_measurement_new_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; + evel_init_option_double(&cpu_use->idle); + evel_init_option_double(&cpu_use->intrpt); + evel_init_option_double(&cpu_use->nice); + evel_init_option_double(&cpu_use->softirq); + evel_init_option_double(&cpu_use->steal); + evel_init_option_double(&cpu_use->sys); + evel_init_option_double(&cpu_use->user); + evel_init_option_double(&cpu_use->wait); + + dlist_push_last(&measurement->cpu_usage, cpu_use); + + EVEL_EXIT(); + return cpu_use; +} + +/**************************************************************************//** + * Set the CPU Idle value in measurement interval + * percentage of CPU time spent in the idle task + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_idle_set(MEASUREMENT_CPU_USE *const cpu_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&cpu_use->idle, val, "CPU idle time"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the percentage of time spent servicing interrupts + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_interrupt_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&cpu_use->intrpt, val, "CPU interrupt value"); + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Set the percentage of time spent running user space processes that have been niced + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_nice_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&cpu_use->nice, val, "CPU nice value"); + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Set the percentage of time spent handling soft irq interrupts + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_softirq_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&cpu_use->softirq, val, "CPU Soft IRQ value"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the percentage of time spent in involuntary wait + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_steal_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&cpu_use->steal, val, "CPU involuntary wait"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the percentage of time spent on system tasks running the kernel + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_system_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&cpu_use->sys, val, "CPU System load"); + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Set the percentage of time spent running un-niced user space processes + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_usageuser_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&cpu_use->user, val, "CPU User load value"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the percentage of CPU time spent waiting for I/O operations to complete + * + * @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 cpu_use Pointer to the CPU Use. + * @param val double + *****************************************************************************/ +void evel_measurement_cpu_use_wait_set(MEASUREMENT_CPU_USE * const cpu_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&cpu_use->wait, val, "CPU Wait IO value"); + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Add an additional Memory 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 Memory identifier. + * @param vmidentifier ASCIIZ string with the VM's identifier. + * @param membuffsz Memory Size. + * + * @return Returns pointer to memory use structure in measurements + *****************************************************************************/ +MEASUREMENT_MEM_USE * evel_measurement_new_mem_use_add(EVENT_MEASUREMENT * measurement, + char * id, char *vmidentifier, double membuffsz) +{ + MEASUREMENT_MEM_USE * mem_use = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(id != NULL); + assert(membuffsz >= 0.0); + + /***************************************************************************/ + /* Allocate a container for the value and push onto the list. */ + /***************************************************************************/ + EVEL_DEBUG("Adding id=%s buffer size=%lf", id, membuffsz); + mem_use = malloc(sizeof(MEASUREMENT_MEM_USE)); + assert(mem_use != NULL); + memset(mem_use, 0, sizeof(MEASUREMENT_MEM_USE)); + mem_use->id = strdup(id); + mem_use->vmid = strdup(vmidentifier); + mem_use->membuffsz = membuffsz; + evel_init_option_double(&mem_use->memcache); + evel_init_option_double(&mem_use->memconfig); + evel_init_option_double(&mem_use->memfree); + evel_init_option_double(&mem_use->slabrecl); + evel_init_option_double(&mem_use->slabunrecl); + evel_init_option_double(&mem_use->memused); + + assert(mem_use->id != NULL); + + dlist_push_last(&measurement->mem_usage, mem_use); + + EVEL_EXIT(); + return mem_use; +} + +/**************************************************************************//** + * Set kilobytes of memory used for cache + * + * @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 mem_use Pointer to the Memory Use. + * @param val double + *****************************************************************************/ +void evel_measurement_mem_use_memcache_set(MEASUREMENT_MEM_USE * const mem_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&mem_use->memcache, val, "Memory cache value"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set kilobytes of memory configured in the virtual machine on which the VNFC reporting + * + * @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 mem_use Pointer to the Memory Use. + * @param val double + *****************************************************************************/ +void evel_measurement_mem_use_memconfig_set(MEASUREMENT_MEM_USE * const mem_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&mem_use->memconfig, val, "Memory configured value"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set kilobytes of physical RAM left unused by the system + * + * @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 mem_use Pointer to the Memory Use. + * @param val double + *****************************************************************************/ +void evel_measurement_mem_use_memfree_set(MEASUREMENT_MEM_USE * const mem_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&mem_use->memfree, val, "Memory freely available value"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the part of the slab that can be reclaimed such as caches measured in kilobytes + * + * @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 mem_use Pointer to the Memory Use. + * @param val double + *****************************************************************************/ +void evel_measurement_mem_use_slab_reclaimed_set(MEASUREMENT_MEM_USE * const mem_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&mem_use->slabrecl, val, "Memory reclaimable slab set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the part of the slab that cannot be reclaimed such as caches measured in kilobytes + * + * @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 mem_use Pointer to the Memory Use. + * @param val double + *****************************************************************************/ +void evel_measurement_mem_use_slab_unreclaimable_set(MEASUREMENT_MEM_USE * const mem_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&mem_use->slabunrecl, val, "Memory unreclaimable slab set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the total memory minus the sum of free, buffered, cached and slab memory in kilobytes + * + * @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 mem_use Pointer to the Memory Use. + * @param val double + *****************************************************************************/ +void evel_measurement_mem_use_usedup_set(MEASUREMENT_MEM_USE * const mem_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&mem_use->memused, val, "Memory usedup total set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an additional Disk 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 Disk utilization. + *****************************************************************************/ +MEASUREMENT_DISK_USE * evel_measurement_new_disk_use_add(EVENT_MEASUREMENT * measurement, char * id) +{ + MEASUREMENT_DISK_USE * disk_use = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(id != NULL); + + /***************************************************************************/ + /* Allocate a container for the value and push onto the list. */ + /***************************************************************************/ + EVEL_DEBUG("Adding id=%s disk usage", id); + disk_use = malloc(sizeof(MEASUREMENT_DISK_USE)); + assert(disk_use != NULL); + memset(disk_use, 0, sizeof(MEASUREMENT_DISK_USE)); + disk_use->id = strdup(id); + assert(disk_use->id != NULL); + dlist_push_last(&measurement->disk_usage, disk_use); + + evel_init_option_double(&disk_use->iotimeavg ); + evel_init_option_double(&disk_use->iotimelast ); + evel_init_option_double(&disk_use->iotimemax ); + evel_init_option_double(&disk_use->iotimemin ); + evel_init_option_double(&disk_use->mergereadavg ); + evel_init_option_double(&disk_use->mergereadlast ); + evel_init_option_double(&disk_use->mergereadmax ); + evel_init_option_double(&disk_use->mergereadmin ); + evel_init_option_double(&disk_use->mergewriteavg ); + evel_init_option_double(&disk_use->mergewritelast ); + evel_init_option_double(&disk_use->mergewritemax ); + evel_init_option_double(&disk_use->mergewritemin ); + evel_init_option_double(&disk_use->octetsreadavg ); + evel_init_option_double(&disk_use->octetsreadlast ); + evel_init_option_double(&disk_use->octetsreadmax ); + evel_init_option_double(&disk_use->octetsreadmin ); + evel_init_option_double(&disk_use->octetswriteavg ); + evel_init_option_double(&disk_use->octetswritelast ); + evel_init_option_double(&disk_use->octetswritemax ); + evel_init_option_double(&disk_use->octetswritemin ); + evel_init_option_double(&disk_use->opsreadavg ); + evel_init_option_double(&disk_use->opsreadlast ); + evel_init_option_double(&disk_use->opsreadmax ); + evel_init_option_double(&disk_use->opsreadmin ); + evel_init_option_double(&disk_use->opswriteavg ); + evel_init_option_double(&disk_use->opswritelast ); + evel_init_option_double(&disk_use->opswritemax ); + evel_init_option_double(&disk_use->opswritemin ); + evel_init_option_double(&disk_use->pendingopsavg ); + evel_init_option_double(&disk_use->pendingopslast ); + evel_init_option_double(&disk_use->pendingopsmax ); + evel_init_option_double(&disk_use->pendingopsmin ); + evel_init_option_double(&disk_use->timereadavg ); + evel_init_option_double(&disk_use->timereadlast ); + evel_init_option_double(&disk_use->timereadmax ); + evel_init_option_double(&disk_use->timereadmin ); + evel_init_option_double(&disk_use->timewriteavg ); + evel_init_option_double(&disk_use->timewritelast ); + evel_init_option_double(&disk_use->timewritemax ); + evel_init_option_double(&disk_use->timewritemin ); + + EVEL_EXIT(); + return disk_use; +} + +/**************************************************************************//** + * Set milliseconds spent doing input/output operations over 1 sec; treat + * this metric as a device load percentage where 1000ms matches 100% load; + * provide the average over the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_iotimeavg_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->iotimeavg, val, "Disk ioload set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set milliseconds spent doing input/output operations over 1 sec; treat + * this metric as a device load percentage where 1000ms matches 100% load; + * provide the last value within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_iotimelast_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->iotimelast, val, "Disk ioloadlast set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set milliseconds spent doing input/output operations over 1 sec; treat + * this metric as a device load percentage where 1000ms matches 100% load; + * provide the maximum value within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_iotimemax_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->iotimemax, val, "Disk ioloadmax set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set milliseconds spent doing input/output operations over 1 sec; treat + * this metric as a device load percentage where 1000ms matches 100% load; + * provide the minimum value within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_iotimemin_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->iotimemin, val, "Disk ioloadmin set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set number of logical read operations that were merged into physical read + * operations, e.g., two logical reads were served by one physical disk access; + * provide the average measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_mergereadavg_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->mergereadavg, val, "Disk Merged read average set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of logical read operations that were merged into physical read + * operations, e.g., two logical reads were served by one physical disk access; + * provide the last measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_mergereadlast_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->mergereadlast, val, "Disk mergedload last set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of logical read operations that were merged into physical read + * operations, e.g., two logical reads were served by one physical disk access; + * provide the maximum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_mergereadmax_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->mergereadmax, val, "Disk merged loadmax set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set number of logical read operations that were merged into physical read + * operations, e.g., two logical reads were served by one physical disk access; + * provide the minimum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_mergereadmin_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->mergereadmin, val, "Disk merged loadmin set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of logical write operations that were merged into physical read + * operations, e.g., two logical writes were served by one physical disk access; + * provide the last measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_mergewritelast_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->mergewritelast, val, "Disk merged writelast set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of logical write operations that were merged into physical read + * operations, e.g., two logical writes were served by one physical disk access; + * provide the maximum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_mergewritemax_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->mergewritemax, val, "Disk writemax set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of logical write operations that were merged into physical read + * operations, e.g., two logical writes were served by one physical disk access; + * provide the maximum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_mergewritemin_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->mergewritemin, val, "Disk writemin set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set number of octets per second read from a disk or partition; + * provide the average measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_octetsreadavg_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->octetsreadavg, val, "Octets readavg set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set number of octets per second read from a disk or partition; + * provide the last measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_octetsreadlast_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->octetsreadlast, val, "Octets readlast set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set number of octets per second read from a disk or partition; + * provide the maximum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_octetsreadmax_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->octetsreadmax, val, "Octets readmax set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of octets per second read from a disk or partition; + * provide the minimum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_octetsreadmin_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->octetsreadmin, val, "Octets readmin set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of octets per second written to a disk or partition; + * provide the average measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_octetswriteavg_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->octetswriteavg, val, "Octets writeavg set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of octets per second written to a disk or partition; + * provide the last measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_octetswritelast_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->octetswritelast, val, "Octets writelast set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of octets per second written to a disk or partition; + * provide the maximum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_octetswritemax_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->octetswritemax, val, "Octets writemax set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of octets per second written to a disk or partition; + * provide the minimum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_octetswritemin_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->octetswritemin, val, "Octets writemin set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set number of read operations per second issued to the disk; + * provide the average measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_opsreadavg_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->opsreadavg, val, "Disk read operation average set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of read operations per second issued to the disk; + * provide the last measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_opsreadlast_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->opsreadlast, val, "Disk read operation last set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of read operations per second issued to the disk; + * provide the maximum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_opsreadmax_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->opsreadmax, val, "Disk read operation maximum set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of read operations per second issued to the disk; + * provide the minimum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_opsreadmin_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->opsreadmin, val, "Disk read operation minimum set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of write operations per second issued to the disk; + * provide the average measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_opswriteavg_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->opswriteavg, val, "Disk write operation average set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of write operations per second issued to the disk; + * provide the last measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_opswritelast_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->opswritelast, val, "Disk write operation last set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set number of write operations per second issued to the disk; + * provide the maximum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_opswritemax_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->opswritemax, val, "Disk write operation maximum set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set number of write operations per second issued to the disk; + * provide the average measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_opswritemin_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->opswritemin, val, "Disk write operation minimum set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set queue size of pending I/O operations per second; + * provide the average measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_pendingopsavg_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->pendingopsavg, val, "Disk pending operation average set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set queue size of pending I/O operations per second; + * provide the last measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_pendingopslast_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->pendingopslast, val, "Disk pending operation last set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set queue size of pending I/O operations per second; + * provide the maximum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_pendingopsmax_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->pendingopsmax, val, "Disk pending operation maximum set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set queue size of pending I/O operations per second; + * provide the minimum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_pendingopsmin_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->pendingopsmin, val, "Disk pending operation min set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set milliseconds a read operation took to complete; + * provide the average measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_timereadavg_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->timereadavg, val, "Disk read time average set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set milliseconds a read operation took to complete; + * provide the last measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_timereadlast_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->timereadlast, val, "Disk read time last set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set milliseconds a read operation took to complete; + * provide the maximum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_timereadmax_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->timereadmax, val, "Disk read time maximum set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set milliseconds a read operation took to complete; + * provide the minimum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_timereadmin_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->timereadmin, val, "Disk read time minimum set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set milliseconds a write operation took to complete; + * provide the average measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_timewriteavg_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->timewriteavg, val, "Disk write time average set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set milliseconds a write operation took to complete; + * provide the last measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_timewritelast_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->timewritelast, val, "Disk write time last set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set milliseconds a write operation took to complete; + * provide the maximum measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_timewritemax_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->timewritemax, val, "Disk write time max set"); + EVEL_EXIT(); +} +/**************************************************************************//** + * Set milliseconds a write operation took to complete; + * provide the average measurement within the measurement interval + * + * @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 disk_use Pointer to the Disk Use. + * @param val double + *****************************************************************************/ +void evel_measurement_disk_use_timewritemin_set(MEASUREMENT_DISK_USE * const disk_use, + const double val) +{ + EVEL_ENTER(); + evel_set_option_double(&disk_use->timewritemin, val, "Disk write time min set"); + 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, + double block_iops, + double ephemeral_configured, + double ephemeral_used, + double 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.0); + assert(ephemeral_configured >= 0.0); + assert(ephemeral_used >= 0.0); + assert(ephemeral_iops >= 0.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 = ephemeral_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 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, + int 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_int(&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_PERFORMANCE 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_PERFORMANCE has immutable + * properties. + * + * @param vnic_id ASCIIZ string with the vNIC's ID. + * @param val_suspect True or false confidence in data. + * + * @returns pointer to the newly manufactured ::MEASUREMENT_VNIC_PERFORMANCE. + * If the structure is not used it must be released using + * ::evel_measurement_free_vnic_performance. + * @retval NULL Failed to create the vNIC Use. + *****************************************************************************/ +MEASUREMENT_VNIC_PERFORMANCE * evel_measurement_new_vnic_performance(char * const vnic_id, + char * const val_suspect) +{ + MEASUREMENT_VNIC_PERFORMANCE * vnic_performance; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(vnic_id != NULL); + assert(!strcmp(val_suspect,"true") || !strcmp(val_suspect,"false")); + + /***************************************************************************/ + /* Allocate, then set Mandatory Parameters. */ + /***************************************************************************/ + EVEL_DEBUG("Adding VNIC ID=%s", vnic_id); + vnic_performance = malloc(sizeof(MEASUREMENT_VNIC_PERFORMANCE)); + assert(vnic_performance != NULL); + vnic_performance->vnic_id = strdup(vnic_id); + vnic_performance->valuesaresuspect = strdup(val_suspect); + + /***************************************************************************/ + /* Initialize Optional Parameters. */ + /***************************************************************************/ + evel_init_option_double(&vnic_performance-> recvd_bcast_packets_acc); + evel_init_option_double(&vnic_performance-> recvd_bcast_packets_delta); + evel_init_option_double(&vnic_performance-> recvd_discarded_packets_acc); + evel_init_option_double(&vnic_performance-> recvd_discarded_packets_delta); + evel_init_option_double(&vnic_performance-> recvd_error_packets_acc); + evel_init_option_double(&vnic_performance-> recvd_error_packets_delta); + evel_init_option_double(&vnic_performance-> recvd_mcast_packets_acc); + evel_init_option_double(&vnic_performance-> recvd_mcast_packets_delta); + evel_init_option_double(&vnic_performance-> recvd_octets_acc); + evel_init_option_double(&vnic_performance-> recvd_octets_delta); + evel_init_option_double(&vnic_performance-> recvd_total_packets_acc); + evel_init_option_double(&vnic_performance-> recvd_total_packets_delta); + evel_init_option_double(&vnic_performance-> recvd_ucast_packets_acc); + evel_init_option_double(&vnic_performance-> recvd_ucast_packets_delta); + evel_init_option_double(&vnic_performance-> tx_bcast_packets_acc); + evel_init_option_double(&vnic_performance-> tx_bcast_packets_delta); + evel_init_option_double(&vnic_performance-> tx_discarded_packets_acc); + evel_init_option_double(&vnic_performance-> tx_discarded_packets_delta); + evel_init_option_double(&vnic_performance-> tx_error_packets_acc); + evel_init_option_double(&vnic_performance-> tx_error_packets_delta); + evel_init_option_double(&vnic_performance-> tx_mcast_packets_acc); + evel_init_option_double(&vnic_performance-> tx_mcast_packets_delta); + evel_init_option_double(&vnic_performance-> tx_octets_acc); + evel_init_option_double(&vnic_performance-> tx_octets_delta); + evel_init_option_double(&vnic_performance-> tx_total_packets_acc); + evel_init_option_double(&vnic_performance-> tx_total_packets_delta); + evel_init_option_double(&vnic_performance-> tx_ucast_packets_acc); + evel_init_option_double(&vnic_performance-> tx_ucast_packets_delta); + + EVEL_EXIT(); + + return vnic_performance; +} + +/**************************************************************************//** + * Free a vNIC Use. + * + * Free off the ::MEASUREMENT_VNIC_PERFORMANCE 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_measurement_free_vnic_performance(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(vnic_performance != NULL); + assert(vnic_performance->vnic_id != NULL); + assert(vnic_performance->valuesaresuspect != NULL); + + /***************************************************************************/ + /* Free the duplicated string. */ + /***************************************************************************/ + free(vnic_performance->vnic_id); + free(vnic_performance->valuesaresuspect); + vnic_performance->vnic_id = NULL; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Accumulated Broadcast Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_bcast_packets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_bcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_bcast_packets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_bcast_packets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_bcast_packets_acc, + recvd_bcast_packets_acc, + "Broadcast Packets accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Broadcast Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_bcast_packets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_bcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_bcast_packets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_bcast_packets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_bcast_packets_delta, + recvd_bcast_packets_delta, + "Delta Broadcast Packets recieved"); + + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Set the Discarded Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_discard_packets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_discard_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_discard_packets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_discard_packets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_discarded_packets_acc, + recvd_discard_packets_acc, + "Discarded Packets accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Discarded Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_discard_packets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_discard_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_discard_packets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_discard_packets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_discarded_packets_delta, + recvd_discard_packets_delta, + "Delta Discarded Packets recieved"); + + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Set the Error Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_error_packets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_error_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_error_packets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_error_packets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_error_packets_acc, + recvd_error_packets_acc, + "Error Packets received accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Error Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_error_packets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_error_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_error_packets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_error_packets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_error_packets_delta, + recvd_error_packets_delta, + "Delta Error Packets recieved"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Accumulated Multicast Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_mcast_packets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_mcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_mcast_packets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_mcast_packets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_mcast_packets_acc, + recvd_mcast_packets_acc, + "Multicast Packets accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Multicast Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_mcast_packets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_mcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_mcast_packets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_mcast_packets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_mcast_packets_delta, + recvd_mcast_packets_delta, + "Delta Multicast Packets recieved"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Accumulated Octets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_octets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_octets_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_octets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_octets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_octets_acc, + recvd_octets_acc, + "Octets received accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Octets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_octets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_octets_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_octets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_octets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_octets_delta, + recvd_octets_delta, + "Delta Octets recieved"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Accumulated Total Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_total_packets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_total_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_total_packets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_total_packets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_total_packets_acc, + recvd_total_packets_acc, + "Total Packets accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Total Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_total_packets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_total_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_total_packets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_total_packets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_total_packets_delta, + recvd_total_packets_delta, + "Delta Total Packets recieved"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Accumulated Unicast Packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_ucast_packets_acc + *****************************************************************************/ +void evel_vnic_performance_rx_ucast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_ucast_packets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_ucast_packets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_ucast_packets_acc, + recvd_ucast_packets_acc, + "Unicast Packets received accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Unicast packets Received in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param recvd_ucast_packets_delta + *****************************************************************************/ +void evel_vnic_performance_rx_ucast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double recvd_ucast_packets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(recvd_ucast_packets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->recvd_ucast_packets_delta, + recvd_ucast_packets_delta, + "Delta Unicast packets recieved"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Transmitted Broadcast Packets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_bcast_packets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_bcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_bcast_packets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_bcast_packets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->tx_bcast_packets_acc, + tx_bcast_packets_acc, + "Transmitted Broadcast Packets accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Broadcast packets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_bcast_packets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_bcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_bcast_packets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_bcast_packets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->tx_bcast_packets_delta, + tx_bcast_packets_delta, + "Delta Transmitted Broadcast packets "); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Transmitted Discarded Packets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_discarded_packets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_discarded_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_discarded_packets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_discarded_packets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->tx_discarded_packets_acc, + tx_discarded_packets_acc, + "Transmitted Discarded Packets accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Discarded packets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_discarded_packets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_discarded_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_discarded_packets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_discarded_packets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->tx_discarded_packets_delta, + tx_discarded_packets_delta, + "Delta Transmitted Discarded packets "); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Transmitted Errored Packets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_error_packets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_error_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_error_packets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_error_packets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->tx_error_packets_acc, + tx_error_packets_acc, + "Transmitted Error Packets accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Errored packets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_error_packets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_error_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_error_packets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_error_packets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->tx_error_packets_delta, + tx_error_packets_delta, + "Delta Transmitted Error packets "); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Transmitted Multicast Packets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_mcast_packets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_mcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_mcast_packets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_mcast_packets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->tx_mcast_packets_acc, + tx_mcast_packets_acc, + "Transmitted Multicast Packets accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Multicast packets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_mcast_packets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_mcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_mcast_packets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_mcast_packets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->tx_mcast_packets_delta, + tx_mcast_packets_delta, + "Delta Transmitted Multicast packets "); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Transmitted Octets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_octets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_octets_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_octets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_octets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->tx_octets_acc, + tx_octets_acc, + "Transmitted Octets accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Octets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_octets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_octets_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_octets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_octets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->tx_octets_delta, + tx_octets_delta, + "Delta Transmitted Octets "); + + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Set the Transmitted Total Packets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_total_packets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_total_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_total_packets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_total_packets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->tx_total_packets_acc, + tx_total_packets_acc, + "Transmitted Total Packets accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Total Packets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_total_packets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_total_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_total_packets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_total_packets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->tx_total_packets_delta, + tx_total_packets_delta, + "Delta Transmitted Total Packets "); + + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Set the Transmitted Unicast Packets in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_ucast_packets_acc + *****************************************************************************/ +void evel_vnic_performance_tx_ucast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_ucast_packets_acc) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_ucast_packets_acc >= 0.0); + + evel_set_option_double(&vnic_performance->tx_ucast_packets_acc, + tx_ucast_packets_acc, + "Transmitted Unicast Packets accumulated"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Delta Octets Transmitted in measurement interval + * property of the vNIC performance. + * + * @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_performance Pointer to the vNIC Use. + * @param tx_ucast_packets_delta + *****************************************************************************/ +void evel_vnic_performance_tx_ucast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, + const double tx_ucast_packets_delta) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(tx_ucast_packets_delta >= 0.0); + + evel_set_option_double(&vnic_performance->tx_ucast_packets_delta, + tx_ucast_packets_delta, + "Delta Transmitted Unicast Packets "); + + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Add an additional vNIC Use to the specified Measurement event. + * + * @param measurement Pointer to the measurement. + * @param vnic_performance Pointer to the vNIC Use to add. + *****************************************************************************/ +void evel_meas_vnic_performance_add(EVENT_MEASUREMENT * const measurement, + MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(measurement != NULL); + assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT); + assert(vnic_performance != NULL); + + dlist_push_last(&measurement->vnic_usage, vnic_performance); + + 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 valset true or false confidence level + * @param recvd_bcast_packets_acc Recieved broadcast packets + * @param recvd_bcast_packets_delta Received delta broadcast packets + * @param recvd_discarded_packets_acc Recieved discarded packets + * @param recvd_discarded_packets_delta Received discarded delta packets + * @param recvd_error_packets_acc Received error packets + * @param recvd_error_packets_delta, Received delta error packets + * @param recvd_mcast_packets_acc Received multicast packets + * @param recvd_mcast_packets_delta Received delta multicast packets + * @param recvd_octets_acc Received octets + * @param recvd_octets_delta Received delta octets + * @param recvd_total_packets_acc Received total packets + * @param recvd_total_packets_delta Received delta total packets + * @param recvd_ucast_packets_acc Received Unicast packets + * @param recvd_ucast_packets_delta Received delta unicast packets + * @param tx_bcast_packets_acc Transmitted broadcast packets + * @param tx_bcast_packets_delta Transmitted delta broadcast packets + * @param tx_discarded_packets_acc Transmitted packets discarded + * @param tx_discarded_packets_delta Transmitted delta discarded packets + * @param tx_error_packets_acc Transmitted error packets + * @param tx_error_packets_delta Transmitted delta error packets + * @param tx_mcast_packets_acc Transmitted multicast packets accumulated + * @param tx_mcast_packets_delta Transmitted delta multicast packets + * @param tx_octets_acc Transmitted octets + * @param tx_octets_delta Transmitted delta octets + * @param tx_total_packets_acc Transmitted total packets + * @param tx_total_packets_delta Transmitted delta total packets + * @param tx_ucast_packets_acc Transmitted Unicast packets + * @param tx_ucast_packets_delta Transmitted delta Unicast packets + *****************************************************************************/ +void evel_measurement_vnic_performance_add(EVENT_MEASUREMENT * const measurement, + char * const vnic_id, + char * valset, + double recvd_bcast_packets_acc, + double recvd_bcast_packets_delta, + double recvd_discarded_packets_acc, + double recvd_discarded_packets_delta, + double recvd_error_packets_acc, + double recvd_error_packets_delta, + double recvd_mcast_packets_acc, + double recvd_mcast_packets_delta, + double recvd_octets_acc, + double recvd_octets_delta, + double recvd_total_packets_acc, + double recvd_total_packets_delta, + double recvd_ucast_packets_acc, + double recvd_ucast_packets_delta, + double tx_bcast_packets_acc, + double tx_bcast_packets_delta, + double tx_discarded_packets_acc, + double tx_discarded_packets_delta, + double tx_error_packets_acc, + double tx_error_packets_delta, + double tx_mcast_packets_acc, + double tx_mcast_packets_delta, + double tx_octets_acc, + double tx_octets_delta, + double tx_total_packets_acc, + double tx_total_packets_delta, + double tx_ucast_packets_acc, + double tx_ucast_packets_delta) +{ + MEASUREMENT_VNIC_PERFORMANCE * vnic_performance = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Trust the assertions in the underlying methods. */ + /***************************************************************************/ + vnic_performance = evel_measurement_new_vnic_performance(vnic_id, valset); + + evel_vnic_performance_rx_bcast_pkt_acc_set(vnic_performance, recvd_bcast_packets_acc); + evel_vnic_performance_rx_bcast_pkt_delta_set(vnic_performance, recvd_bcast_packets_delta); + evel_vnic_performance_rx_discard_pkt_acc_set(vnic_performance, recvd_discarded_packets_acc); + evel_vnic_performance_rx_discard_pkt_delta_set(vnic_performance, recvd_discarded_packets_delta); + evel_vnic_performance_rx_error_pkt_acc_set(vnic_performance, recvd_error_packets_acc); + evel_vnic_performance_rx_error_pkt_delta_set(vnic_performance, recvd_error_packets_delta); + evel_vnic_performance_rx_mcast_pkt_acc_set(vnic_performance, recvd_mcast_packets_acc); + evel_vnic_performance_rx_mcast_pkt_delta_set(vnic_performance, recvd_mcast_packets_delta); + evel_vnic_performance_rx_octets_acc_set(vnic_performance, recvd_octets_acc); + evel_vnic_performance_rx_octets_delta_set(vnic_performance, recvd_octets_delta); + evel_vnic_performance_rx_total_pkt_acc_set(vnic_performance, recvd_total_packets_acc); + evel_vnic_performance_rx_total_pkt_delta_set(vnic_performance, recvd_total_packets_delta); + evel_vnic_performance_rx_ucast_pkt_acc_set(vnic_performance, recvd_ucast_packets_acc); + evel_vnic_performance_rx_ucast_pkt_delta_set(vnic_performance, recvd_ucast_packets_delta); + evel_vnic_performance_tx_bcast_pkt_acc_set(vnic_performance, tx_bcast_packets_acc); + evel_vnic_performance_tx_bcast_pkt_delta_set(vnic_performance, tx_bcast_packets_delta); + evel_vnic_performance_tx_discarded_pkt_acc_set(vnic_performance, tx_discarded_packets_acc); + evel_vnic_performance_tx_discarded_pkt_delta_set(vnic_performance, tx_discarded_packets_delta); + evel_vnic_performance_tx_error_pkt_acc_set(vnic_performance, tx_error_packets_acc); + evel_vnic_performance_tx_error_pkt_delta_set(vnic_performance, tx_error_packets_delta); + evel_vnic_performance_tx_mcast_pkt_acc_set(vnic_performance, tx_mcast_packets_acc); + evel_vnic_performance_tx_mcast_pkt_delta_set(vnic_performance, tx_mcast_packets_delta); + evel_vnic_performance_tx_octets_acc_set(vnic_performance, tx_octets_acc); + evel_vnic_performance_tx_octets_delta_set(vnic_performance, tx_octets_delta); + evel_vnic_performance_tx_total_pkt_acc_set(vnic_performance, tx_total_packets_acc); + evel_vnic_performance_tx_total_pkt_delta_set(vnic_performance, tx_total_packets_delta); + evel_vnic_performance_tx_ucast_pkt_acc_set(vnic_performance, tx_ucast_packets_acc); + evel_vnic_performance_tx_ucast_pkt_delta_set(vnic_performance, tx_ucast_packets_delta); + evel_meas_vnic_performance_add(measurement, vnic_performance); +} + +/**************************************************************************//** + * 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_MEM_USE * mem_use = NULL; + MEASUREMENT_DISK_USE * disk_use = NULL; + MEASUREMENT_FSYS_USE * fsys_use = NULL; + MEASUREMENT_LATENCY_BUCKET * bucket = NULL; + MEASUREMENT_VNIC_PERFORMANCE * vnic_performance = 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; + DLIST_ITEM * addl_info_item = NULL; + OTHER_FIELD *addl_info = 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_int(jbuf, "measurementInterval", event->measurement_interval); + + /***************************************************************************/ + /* Optional fields. */ + /***************************************************************************/ + // additional fields + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "additionalFields")) + { + bool item_added = false; + + addl_info_item = dlist_get_first(&event->additional_info); + while (addl_info_item != NULL) + { + addl_info = (OTHER_FIELD*) addl_info_item->item; + assert(addl_info != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "additionalFields", + 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); + } + } + + // TBD additional json objects + 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_opt_double(jbuf, "cpuIdle", &cpu_use->idle); + evel_enc_kv_opt_double(jbuf, "cpuUsageInterrupt", &cpu_use->intrpt); + evel_enc_kv_opt_double(jbuf, "cpuUsageNice", &cpu_use->nice); + evel_enc_kv_opt_double(jbuf, "cpuUsageSoftIrq", &cpu_use->softirq); + evel_enc_kv_opt_double(jbuf, "cpuUsageSteal", &cpu_use->steal); + evel_enc_kv_opt_double(jbuf, "cpuUsageSystem", &cpu_use->sys); + evel_enc_kv_opt_double(jbuf, "cpuUsageUser", &cpu_use->user); + evel_enc_kv_opt_double(jbuf, "cpuWait", &cpu_use->wait); + 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); + } + } + + + /***************************************************************************/ + /* Disk Use list. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "diskUsageArray")) + { + bool item_added = false; + + item = dlist_get_first(&event->disk_usage); + while (item != NULL) + { + disk_use = (MEASUREMENT_DISK_USE*) item->item; + assert(disk_use != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "diskUsageArray", + disk_use->id)) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "diskIdentifier", disk_use->id); + evel_enc_kv_opt_double(jbuf, "diskIoTimeAvg", &disk_use->iotimeavg); + evel_enc_kv_opt_double(jbuf, "diskIoTimeLast", &disk_use->iotimelast); + evel_enc_kv_opt_double(jbuf, "diskIoTimeMax", &disk_use->iotimemax); + evel_enc_kv_opt_double(jbuf, "diskIoTimeMin", &disk_use->iotimemin); + evel_enc_kv_opt_double(jbuf, "diskMergedReadAvg", &disk_use->mergereadavg); + evel_enc_kv_opt_double(jbuf, "diskMergedReadLast", &disk_use->mergereadlast); + evel_enc_kv_opt_double(jbuf, "diskMergedReadMax", &disk_use->mergereadmax); + evel_enc_kv_opt_double(jbuf, "diskMergedReadMin", &disk_use->mergereadmin); + evel_enc_kv_opt_double(jbuf, "diskMergedWriteAvg", &disk_use->mergewriteavg); + evel_enc_kv_opt_double(jbuf, "diskMergedWriteLast", &disk_use->mergewritelast); + evel_enc_kv_opt_double(jbuf, "diskMergedWriteMax", &disk_use->mergewritemax); + evel_enc_kv_opt_double(jbuf, "diskMergedWriteMin", &disk_use->mergewritemin); + evel_enc_kv_opt_double(jbuf, "diskOctetsReadAvg", &disk_use->octetsreadavg); + evel_enc_kv_opt_double(jbuf, "diskOctetsReadLast", &disk_use->octetsreadlast); + evel_enc_kv_opt_double(jbuf, "diskOctetsReadMax", &disk_use->octetsreadmax); + evel_enc_kv_opt_double(jbuf, "diskOctetsReadMin", &disk_use->octetsreadmin); + evel_enc_kv_opt_double(jbuf, "diskOctetsWriteAvg", &disk_use->octetswriteavg); + evel_enc_kv_opt_double(jbuf, "diskOctetsWriteLast", &disk_use->octetswritelast); + evel_enc_kv_opt_double(jbuf, "diskOctetsWriteMax", &disk_use->octetswritemax); + evel_enc_kv_opt_double(jbuf, "diskOctetsWriteMin", &disk_use->octetswritemin); + evel_enc_kv_opt_double(jbuf, "diskOpsReadAvg", &disk_use->opsreadavg); + evel_enc_kv_opt_double(jbuf, "diskOpsReadLast", &disk_use->opsreadlast); + evel_enc_kv_opt_double(jbuf, "diskOpsReadMax", &disk_use->opsreadmax); + evel_enc_kv_opt_double(jbuf, "diskOpsReadMin", &disk_use->opsreadmin); + evel_enc_kv_opt_double(jbuf, "diskOpsWriteAvg", &disk_use->opswriteavg); + evel_enc_kv_opt_double(jbuf, "diskOpsWriteLast", &disk_use->opswritelast); + evel_enc_kv_opt_double(jbuf, "diskOpsWriteMax", &disk_use->opswritemax); + evel_enc_kv_opt_double(jbuf, "diskOpsWriteMin", &disk_use->opswritemin); + evel_enc_kv_opt_double(jbuf, "diskPendingOperationsAvg", &disk_use->pendingopsavg); + evel_enc_kv_opt_double(jbuf, "diskPendingOperationsLast", &disk_use->pendingopslast); + evel_enc_kv_opt_double(jbuf, "diskPendingOperationsMax", &disk_use->pendingopsmax); + evel_enc_kv_opt_double(jbuf, "diskPendingOperationsMin", &disk_use->pendingopsmin); + evel_enc_kv_opt_double(jbuf, "diskTimeReadAvg", &disk_use->timereadavg); + evel_enc_kv_opt_double(jbuf, "diskTimeReadLast", &disk_use->timereadlast); + evel_enc_kv_opt_double(jbuf, "diskTimeReadMax", &disk_use->timereadmax); + evel_enc_kv_opt_double(jbuf, "diskTimeReadMin", &disk_use->timereadmin); + evel_enc_kv_opt_double(jbuf, "diskTimeWriteAvg", &disk_use->timewriteavg); + evel_enc_kv_opt_double(jbuf, "diskTimeWriteLast", &disk_use->timewritelast); + evel_enc_kv_opt_double(jbuf, "diskTimeWriteMax", &disk_use->timewritemax); + evel_enc_kv_opt_double(jbuf, "diskTimeWriteMin", &disk_use->timewritemin); + 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_string(jbuf, "filesystemName", fsys_use->filesystem_name); + evel_enc_kv_double( + jbuf, "blockConfigured", fsys_use->block_configured); + evel_enc_kv_double(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_double(jbuf, "ephemeralIops", fsys_use->ephemeral_iops); + evel_enc_kv_double(jbuf, "ephemeralUsed", fsys_use->ephemeral_used); + 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_int(jbuf, "requestRate", &event->request_rate); + + /***************************************************************************/ + /* vNIC Usage TBD Performance array */ + /***************************************************************************/ + 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_performance = (MEASUREMENT_VNIC_PERFORMANCE *) item->item; + assert(vnic_performance != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "vNicPerformanceArray", + vnic_performance->vnic_id)) + { + evel_json_open_object(jbuf); + + /*********************************************************************/ + /* Optional fields. */ + /*********************************************************************/ + evel_enc_kv_opt_double( jbuf, + "receivedBroadcastPacketsAccumulated", &vnic_performance->recvd_bcast_packets_acc); + evel_enc_kv_opt_double( jbuf, + "receivedBroadcastPacketsDelta", &vnic_performance->recvd_bcast_packets_delta); + evel_enc_kv_opt_double( jbuf, + "receivedDiscardedPacketsAccumulated", &vnic_performance->recvd_discarded_packets_acc); + evel_enc_kv_opt_double( jbuf, + "receivedDiscardedPacketsDelta", &vnic_performance->recvd_discarded_packets_delta); + evel_enc_kv_opt_double( jbuf, + "receivedErrorPacketsAccumulated", &vnic_performance->recvd_error_packets_acc); + evel_enc_kv_opt_double( jbuf, + "receivedErrorPacketsDelta", &vnic_performance->recvd_error_packets_delta); + evel_enc_kv_opt_double( jbuf, + "receivedMulticastPacketsAccumulated", &vnic_performance->recvd_mcast_packets_acc); + evel_enc_kv_opt_double( jbuf, + "receivedMulticastPacketsDelta", &vnic_performance->recvd_mcast_packets_delta); + evel_enc_kv_opt_double( jbuf, + "receivedOctetsAccumulated", &vnic_performance->recvd_octets_acc); + evel_enc_kv_opt_double( jbuf, + "receivedOctetsDelta", &vnic_performance->recvd_octets_delta); + evel_enc_kv_opt_double( jbuf, + "receivedTotalPacketsAccumulated", &vnic_performance->recvd_total_packets_acc); + evel_enc_kv_opt_double( jbuf, + "receivedTotalPacketsDelta", &vnic_performance->recvd_total_packets_delta); + evel_enc_kv_opt_double( jbuf, + "receivedUnicastPacketsAccumulated", &vnic_performance->recvd_ucast_packets_acc); + evel_enc_kv_opt_double( jbuf, + "receivedUnicastPacketsDelta", &vnic_performance->recvd_ucast_packets_delta); + evel_enc_kv_opt_double( jbuf, + "transmittedBroadcastPacketsAccumulated", &vnic_performance->tx_bcast_packets_acc); + evel_enc_kv_opt_double( jbuf, + "transmittedBroadcastPacketsDelta", &vnic_performance->tx_bcast_packets_delta); + evel_enc_kv_opt_double( jbuf, + "transmittedDiscardedPacketsAccumulated", &vnic_performance->tx_discarded_packets_acc); + evel_enc_kv_opt_double( jbuf, + "transmittedDiscardedPacketsDelta", &vnic_performance->tx_discarded_packets_delta); + evel_enc_kv_opt_double( jbuf, + "transmittedErrorPacketsAccumulated", &vnic_performance->tx_error_packets_acc); + evel_enc_kv_opt_double( jbuf, + "transmittedErrorPacketsDelta", &vnic_performance->tx_error_packets_delta); + evel_enc_kv_opt_double( jbuf, + "transmittedMulticastPacketsAccumulated", &vnic_performance->tx_mcast_packets_acc); + evel_enc_kv_opt_double( jbuf, + "transmittedMulticastPacketsDelta", &vnic_performance->tx_mcast_packets_delta); + evel_enc_kv_opt_double( jbuf, + "transmittedOctetsAccumulated", &vnic_performance->tx_octets_acc); + evel_enc_kv_opt_double( jbuf, + "transmittedOctetsDelta", &vnic_performance->tx_octets_delta); + evel_enc_kv_opt_double( jbuf, + "transmittedTotalPacketsAccumulated", &vnic_performance->tx_total_packets_acc); + evel_enc_kv_opt_double( jbuf, + "transmittedTotalPacketsDelta", &vnic_performance->tx_total_packets_delta); + evel_enc_kv_opt_double( jbuf, + "transmittedUnicastPacketsAccumulated", &vnic_performance->tx_ucast_packets_acc); + evel_enc_kv_opt_double( jbuf, + "transmittedUnicastPacketsDelta", &vnic_performance->tx_ucast_packets_delta); + + /*********************************************************************/ + /* Mandatory fields. */ + /*********************************************************************/ + evel_enc_kv_string(jbuf, "valuesAreSuspect", vnic_performance->valuesaresuspect); + evel_enc_kv_string(jbuf, "vNicIdentifier", vnic_performance->vnic_id); + + 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); + } + } + + + /***************************************************************************/ + /* Memory Use list. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "memoryUsageArray")) + { + bool item_added = false; + + item = dlist_get_first(&event->mem_usage); + while (item != NULL) + { + mem_use = (MEASUREMENT_MEM_USE*) item->item; + assert(mem_use != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "memoryUsageArray", + mem_use->id)) + { + evel_json_open_object(jbuf); + evel_enc_kv_double(jbuf, "memoryBuffered", mem_use->membuffsz); + evel_enc_kv_opt_double(jbuf, "memoryCached", &mem_use->memcache); + evel_enc_kv_opt_double(jbuf, "memoryConfigured", &mem_use->memconfig); + evel_enc_kv_opt_double(jbuf, "memoryFree", &mem_use->memfree); + evel_enc_kv_opt_double(jbuf, "memorySlabRecl", &mem_use->slabrecl); + evel_enc_kv_opt_double(jbuf, "memorySlabUnrecl", &mem_use->slabunrecl); + evel_enc_kv_opt_double(jbuf, "memoryUsed", &mem_use->memused); + evel_enc_kv_string(jbuf, "vmIdentifier", mem_use->id); + 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_int( + jbuf, "numberOfMediaPortsInUse", &event->media_ports_in_use); + evel_enc_kv_opt_int( + 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->minor_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_DISK_USE * disk_use = NULL; + MEASUREMENT_FSYS_USE * fsys_use = NULL; + MEASUREMENT_LATENCY_BUCKET * bucket = NULL; + MEASUREMENT_MEM_USE * mem_use = NULL; + MEASUREMENT_VNIC_PERFORMANCE * vnic_performance = NULL; + MEASUREMENT_FEATURE_USE * feature_use = NULL; + MEASUREMENT_CODEC_USE * codec_use = NULL; + MEASUREMENT_GROUP * measurement_group = NULL; + CUSTOM_MEASUREMENT * measurement = NULL; + OTHER_FIELD *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_MEASUREMENT); + + /***************************************************************************/ + /* 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); + } + + + + 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); + } + disk_use = dlist_pop_last(&event->disk_usage); + while (disk_use != NULL) + { + EVEL_DEBUG("Freeing Disk use Info (%s)", disk_use->id); + free(disk_use->id); + free(disk_use); + disk_use = dlist_pop_last(&event->disk_usage); + } + mem_use = dlist_pop_last(&event->mem_usage); + while (mem_use != NULL) + { + EVEL_DEBUG("Freeing Memory use Info (%s)", mem_use->id); + free(mem_use->id); + free(mem_use->vmid); + free(mem_use); + mem_use = dlist_pop_last(&event->mem_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_performance = dlist_pop_last(&event->vnic_usage); + while (vnic_performance != NULL) + { + EVEL_DEBUG("Freeing vNIC performance Info (%s)", vnic_performance->vnic_id); + evel_measurement_free_vnic_performance(vnic_performance); + free(vnic_performance); + vnic_performance = 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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_sipsignaling.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_sipsignaling.c new file mode 100644 index 0000000..45f5348 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_sipsignaling.c @@ -0,0 +1,574 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to Signaling. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#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 event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc + * @param vendor_name The vendor id to encode in the event vnf field. + * @param module The module to encode in the event. + * @param vnfname The Virtual network function to encode in the event. + * @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* ev_name, const char *ev_id, + const char * const vendor_name, + const char * const correlator, + const char * const local_ip_address, + const char * const local_port, + const char * const remote_ip_address, + const char * const remote_port) +{ + EVENT_SIGNALING * event = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(vendor_name != 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_nameid(&event->header,ev_name,ev_id); + event->header.event_domain = EVEL_DOMAIN_SIPSIGNALING; + event->major_version = EVEL_SIGNALING_MAJOR_VERSION; + event->minor_version = EVEL_SIGNALING_MINOR_VERSION; + evel_init_vendor_field(&event->vnfname_field, vendor_name); + evel_set_option_string(&event->correlator,correlator,"Init correlator"); + evel_set_option_string(&event->local_ip_address,local_ip_address,"Init correlator"); + evel_set_option_string(&event->local_port,local_port,"Init local port"); + evel_set_option_string(&event->remote_ip_address,remote_ip_address,"Init remote ip"); + evel_set_option_string(&event->remote_port,remote_port,"Init remote port"); + evel_init_option_string(&event->compressed_sip); + evel_init_option_string(&event->summary_sip); + dlist_initialize(&event->additional_info); + +exit_label: + + EVEL_EXIT(); + return event; +} + +/**************************************************************************//** + * Add an additional value name/value pair to the SIP signaling. + * + * 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 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_signaling_addl_info_add(EVENT_SIGNALING * event, char * name, char * value) +{ + FAULT_ADDL_INFO * addl_info = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIPSIGNALING); + assert(name != NULL); + assert(value != NULL); + + EVEL_DEBUG("Adding name=%s value=%s", name, value); + addl_info = malloc(sizeof(SIGNALING_ADDL_FIELD)); + assert(addl_info != NULL); + memset(addl_info, 0, sizeof(SIGNALING_ADDL_FIELD)); + addl_info->name = strdup(name); + addl_info->value = strdup(value); + assert(addl_info->name != NULL); + assert(addl_info->value != NULL); + + dlist_push_last(&event->additional_info, addl_info); + + EVEL_EXIT(); +} + + +/**************************************************************************//** + * 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_SIPSIGNALING); + 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_SIPSIGNALING); + 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_SIPSIGNALING); + 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_SIPSIGNALING); + 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_SIPSIGNALING); + assert(remote_port != NULL); + + evel_set_option_string(&event->remote_port, + remote_port, + "Remote Port"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Vendor module 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 modulename The module name to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_signaling_vnfmodule_name_set(EVENT_SIGNALING * const event, + const char * const module_name) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIPSIGNALING); + assert(module_name != NULL); + + evel_vendor_field_module_set(&event->vnfname_field, module_name); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Vendor module 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 vnfname The Virtual Network function to be set. ASCIIZ string. + * The caller does not need to preserve the value once + * the function returns. + *****************************************************************************/ +void evel_signaling_vnfname_set(EVENT_SIGNALING * const event, + const char * const vnfname) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIPSIGNALING); + assert(vnfname != NULL); + + evel_vendor_field_vnfname_set(&event->vnfname_field, vnfname); + + 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_SIPSIGNALING); + 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_SIPSIGNALING); + assert(summary_sip != NULL); + + evel_set_option_string(&event->summary_sip, + summary_sip, + "Summary SIP"); + + 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_SIPSIGNALING); + 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) +{ + SIGNALING_ADDL_FIELD * addl_info = NULL; + DLIST_ITEM * addl_info_item = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_SIPSIGNALING); + + evel_json_encode_header(jbuf, &event->header); + evel_json_open_named_object(jbuf, "signalingFields"); + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + evel_enc_kv_opt_string(jbuf, "compressedSip", &event->compressed_sip); + 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_version(jbuf, "signalingFieldsVersion", event->major_version,event->minor_version); + evel_enc_kv_opt_string(jbuf, "summarySip", &event->summary_sip); + evel_json_encode_vendor_field(jbuf, &event->vnfname_field); + + + /***************************************************************************/ + /* Checkpoint, so that we can wind back if all fields are suppressed. */ + /***************************************************************************/ + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "additionalInformation")) + { + bool item_added = false; + + addl_info_item = dlist_get_first(&event->additional_info); + while (addl_info_item != NULL) + { + addl_info = (SIGNALING_ADDL_FIELD*) addl_info_item->item; + assert(addl_info != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "additionalInformation", + 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_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) +{ + SIGNALING_ADDL_FIELD * 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_SIPSIGNALING); + + /***************************************************************************/ + /* 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); + } + + evel_free_event_vendor_field(&event->vnfname_field); + 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_free_header(&event->header); + + EVEL_EXIT(); +} diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_state_change.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_state_change.c new file mode 100644 index 0000000..8915afa --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_state_change.c @@ -0,0 +1,286 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the State Change. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#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 event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc + * @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 char* ev_name, + const char *ev_id, + 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_nameid(&state_change->header,ev_name,ev_id); + 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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_strings.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_strings.c new file mode 100644 index 0000000..96db59b --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_strings.c @@ -0,0 +1,473 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * Implementation of EVEL functions to convert common enum types to strings. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#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_HEARTBEAT_FIELD: + result = "heartbeat"; + break; + + case EVEL_DOMAIN_SIPSIGNALING: + result = "sipSignaling"; + break; + + case EVEL_DOMAIN_STATE_CHANGE: + result = "stateChange"; + break; + + case EVEL_DOMAIN_SYSLOG: + result = "syslog"; + break; + + case EVEL_DOMAIN_OTHER: + result = "other"; + break; + + case EVEL_DOMAIN_VOICE_QUALITY: + result = "voiceQuality"; + break; + + case EVEL_DOMAIN_THRESHOLD_CROSS: + result = "thresholdCrossingAlert"; + 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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_syslog.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_syslog.c new file mode 100644 index 0000000..85b0ec9 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_syslog.c @@ -0,0 +1,505 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the Syslog. + * + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#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_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc + * @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(const char* ev_name, const char *ev_id, + 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_nameid(&syslog->header,ev_name,ev_id); + 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); + 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->additional_filters); + evel_init_option_string(&syslog->event_source_host); + evel_init_option_string(&syslog->syslog_proc); + evel_init_option_string(&syslog->syslog_s_data); + evel_init_option_string(&syslog->syslog_sdid); + evel_init_option_string(&syslog->syslog_severity); + +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_filter_set(EVENT_SYSLOG * syslog, + char * filter) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(syslog != NULL); + assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG); + assert(filter != NULL); + + evel_set_option_string(&syslog->additional_filters, + filter, + "Syslog filter string"); + + 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(); +} + +/**************************************************************************//** + * Set the Structured SDID 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 sdid The Structured Data to be set. ASCIIZ string. name@number + * Caller does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_sdid_set(EVENT_SYSLOG * syslog, const char * const sdid) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(syslog != NULL); + assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG); + assert(sdid != NULL); + + evel_set_option_string(&syslog->syslog_sdid, + sdid, + "SdId set"); + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Structured Severity 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 sdid The Structured Data to be set. ASCIIZ string. + * Caller does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_syslog_severity_set(EVENT_SYSLOG * syslog, const char * const severty) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(syslog != NULL); + assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG); + assert(severty != NULL); + + if( !strcmp(severty,"Alert") || !strcmp(severty,"Critical") || !strcmp(severty,"Debug") || + !strcmp(severty,"Emergency") || !strcmp(severty,"Error") || !strcmp(severty,"Info") || + !strcmp(severty,"Notice") || !strcmp(severty,"Warning") ) + { + evel_set_option_string(&syslog->syslog_severity, + severty, + "Severity set"); + } + 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; + + 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"); + + evel_enc_kv_opt_string(jbuf, "additionalFields", &event->additional_filters); + /***************************************************************************/ + /* 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_enc_kv_opt_string(jbuf, "eventSourceHost", &event->event_source_host); + evel_enc_kv_opt_int(jbuf, "syslogFacility", &event->syslog_facility); + evel_enc_kv_opt_int(jbuf, "syslogPri", &event->syslog_priority); + 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_string(jbuf, "syslogSdId", &event->syslog_sdid); + evel_enc_kv_opt_string(jbuf, "syslogSev", &event->syslog_severity); + 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) +{ + + 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. */ + /***************************************************************************/ + + evel_free_option_string(&event->additional_filters); + 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); + evel_free_option_string(&event->syslog_sdid); + evel_free_option_string(&event->syslog_severity); + free(event->syslog_tag); + evel_free_header(&event->header); + + EVEL_EXIT(); +} diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_threshold_cross.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_threshold_cross.c new file mode 100644 index 0000000..f4fa620 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_threshold_cross.c @@ -0,0 +1,531 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the Threshold Cross Alerts. + * + *****************************************************************************/ +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include "evel.h" +#include "evel_internal.h" +#include "evel_throttle.h" + + +/**************************************************************************//** + * Create a new Threshold Crossing Alert event. + * + * @note The mandatory fields on the TCA 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 + * TCA has immutable properties. + * + * @param event_name Unique Event Name confirming Domain AsdcVnfModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc + * @param char* tcriticality Performance Counter Criticality MAJ MIN, + * @param char* tname Performance Counter Threshold name + * @param char* tthresholdCrossed Counter Threshold crossed value + * @param char* tvalue Counter actual value + * @param EVEL_EVENT_ACTION talertAction Alert set continue or clear + * @param char* talertDescription + * @param EVEL_ALERT_TYPE talertType Kind of anamoly + * @param unsigned long long tcollectionTimestamp time at which alert was collected + * @param EVEL_SEVERITIES teventSeverity Severity of Alert + * @param unsigned long long teventStartTimestamp Time when this alert started + * + * @returns pointer to the newly manufactured ::EVENT_THRESHOLD_CROSS. If the + * event is not used it must be released using + * ::evel_free_threshold_cross + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_THRESHOLD_CROSS * evel_new_threshold_cross(const char * ev_name, const char * ev_id, + char * tcriticality, + char * tname, + char * tthresholdCrossed, + char * tvalue, + EVEL_EVENT_ACTION talertAction, + char * talertDescription, + EVEL_ALERT_TYPE talertType, + unsigned long long tcollectionTimestamp, + EVEL_SEVERITIES teventSeverity, + unsigned long long teventStartTimestamp ) +{ + EVENT_THRESHOLD_CROSS * event = NULL; + EVEL_ENTER(); + + assert( tcriticality!= NULL ); + assert( tname!= NULL ); + assert( tthresholdCrossed != NULL ); + assert( tvalue!= NULL ); + assert( talertDescription != NULL ); + + + /***************************************************************************/ + /* Allocate the Threshold crossing event. */ + /***************************************************************************/ + event = malloc(sizeof(EVENT_THRESHOLD_CROSS)); + if (event == NULL) + { + log_error_state("Out of memory"); + goto exit_label; + } + memset(event, 0, sizeof(EVENT_THRESHOLD_CROSS)); + EVEL_DEBUG("New Threshold Cross event is at %lp", event); + + /***************************************************************************/ + /* Initialize the header & the threshold crossing fields. */ + /***************************************************************************/ + evel_init_header_nameid(&event->header,ev_name,ev_id); + event->header.event_domain = EVEL_DOMAIN_THRESHOLD_CROSS; + event->major_version = EVEL_THRESHOLD_CROSS_MAJOR_VERSION; + event->minor_version = EVEL_THRESHOLD_CROSS_MINOR_VERSION; + + + event->additionalParameters.criticality = strdup(tcriticality); + event->additionalParameters.name = strdup(tname); + event->additionalParameters.thresholdCrossed = strdup(tthresholdCrossed); + event->additionalParameters.value = strdup(tvalue); + event->alertAction = talertAction; + event->alertDescription = strdup(talertDescription); + event->alertType = talertType; + event->collectionTimestamp = tcollectionTimestamp; + event->eventSeverity = teventSeverity; + event->eventStartTimestamp = teventStartTimestamp; + + evel_init_option_string(&event->alertValue); + evel_init_option_string(&event->dataCollector); + evel_init_option_string(&event->elementType); + evel_init_option_string(&event->interfaceName); + evel_init_option_string(&event->networkService); + evel_init_option_string(&event->possibleRootCause); + dlist_initialize(&event->additional_info); + dlist_initialize(&event->alertidList); + +exit_label: + + EVEL_EXIT(); + return event; + +} + + +/**************************************************************************//** + * Set the Event Type property of the TC Alert. + * + * @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 type The Event Type to be set. ASCIIZ string. The caller + * does not need to preserve the value once the function + * returns. + *****************************************************************************/ +void evel_threshold_cross_type_set(EVENT_THRESHOLD_CROSS * const event,char * type) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions and call evel_header_type_set. */ + /***************************************************************************/ + assert(type!=NULL); + assert(event->header.event_domain == EVEL_DOMAIN_THRESHOLD_CROSS); + evel_header_type_set(&event->header, type); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an optional additional alertid value to Alert. + * + *****************************************************************************/ +void evel_threshold_cross_alertid_add(EVENT_THRESHOLD_CROSS * const event,char * alertid) +{ + char *alid=NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_THRESHOLD_CROSS); + assert(alertid != NULL); + + EVEL_DEBUG("Adding AlertId=%s", alertid); + alid = strdup(alertid); + assert(alid != NULL); + + dlist_push_last(&event->alertidList, alid); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an optional additional value name/value pair to the Alert. + * + * 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 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_threshold_cross_addl_info_add(EVENT_THRESHOLD_CROSS * const event, const char * name, const char * value) +{ + OTHER_FIELD * nv_pair = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_THRESHOLD_CROSS); + 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_info, nv_pair); + + 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_threshold_cross(EVENT_THRESHOLD_CROSS * const event) +{ + OTHER_FIELD * addl_info = NULL; + char *ptr; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the API. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_THRESHOLD_CROSS); + + /***************************************************************************/ + /* 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); + } + ptr = dlist_pop_last(&event->alertidList); + while (ptr != NULL) + { + free(ptr); + ptr = dlist_pop_last(&event->alertidList); + } + + free(event->additionalParameters.criticality); + free(event->additionalParameters.name); + free(event->additionalParameters.thresholdCrossed); + free(event->additionalParameters.value); + free(event->alertDescription); + + evel_free_option_string(&event->alertValue); + evel_free_option_string(&event->dataCollector); + evel_free_option_string(&event->elementType); + evel_free_option_string(&event->interfaceName); + evel_free_option_string(&event->networkService); + evel_free_option_string(&event->possibleRootCause); + evel_free_header(&event->header); + + EVEL_EXIT(); +} + + /**************************************************************************//** + * Set the TCA probable Root cause. + * + * @param sheader Possible root cause to Threshold + *****************************************************************************/ + void evel_threshold_cross_possible_rootcause_set(EVENT_THRESHOLD_CROSS * const event, char * sheader) + { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event->header.event_domain == EVEL_DOMAIN_THRESHOLD_CROSS); + assert(sheader != NULL); + + evel_set_option_string(&event->possibleRootCause, + sheader, + "Rootcause value"); + + EVEL_EXIT(); + } + + /**************************************************************************//** + * Set the TCA networking cause. + * + * @param sheader Possible networking service value to Threshold + *****************************************************************************/ + void evel_threshold_cross_networkservice_set(EVENT_THRESHOLD_CROSS * const event, char * sheader) + { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event->header.event_domain == EVEL_DOMAIN_THRESHOLD_CROSS); + assert(sheader != NULL); + + evel_set_option_string(&event->networkService, + sheader, + "Networking service value"); + + EVEL_EXIT(); + } + + /**************************************************************************//** + * Set the TCA Interface name. + * + * @param sheader Interface name to threshold + *****************************************************************************/ + void evel_threshold_cross_interfacename_set(EVENT_THRESHOLD_CROSS * const event,char * sheader) + { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event->header.event_domain == EVEL_DOMAIN_THRESHOLD_CROSS); + assert(sheader != NULL); + + evel_set_option_string(&event->interfaceName, + sheader, + "TCA Interface name"); + EVEL_EXIT(); + } + + /**************************************************************************//** + * Set the TCA Data element type. + * + * @param sheader element type of Threshold + *****************************************************************************/ + void evel_threshold_cross_data_elementtype_set(EVENT_THRESHOLD_CROSS * const event,char * sheader) + { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event->header.event_domain == EVEL_DOMAIN_THRESHOLD_CROSS); + assert(sheader != NULL); + + evel_set_option_string(&event->elementType, + sheader, + "TCA Element type value"); + EVEL_EXIT(); + } + + /**************************************************************************//** + * Set the TCA Data collector value. + * + * @param sheader Data collector value + *****************************************************************************/ + void evel_threshold_cross_data_collector_set(EVENT_THRESHOLD_CROSS * const event,char * sheader) + { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event->header.event_domain == EVEL_DOMAIN_THRESHOLD_CROSS); + assert(sheader != NULL); + + evel_set_option_string(&event->dataCollector, + sheader, + "Datacollector value"); + EVEL_EXIT(); + } + + + + /**************************************************************************//** + * Set the TCA alert value. + * + * @param sheader Possible alert value + *****************************************************************************/ + void evel_threshold_cross_alertvalue_set(EVENT_THRESHOLD_CROSS * const event,char * sheader) + { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event->header.event_domain == EVEL_DOMAIN_THRESHOLD_CROSS); + assert(sheader != NULL); + + evel_set_option_string(&event->alertValue, + sheader, + "Alert value"); + 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_perf_counter( EVEL_JSON_BUFFER * jbuf, PERF_COUNTER *pcounter) +{ + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(jbuf != NULL); + assert(pcounter != NULL); + + evel_json_open_named_object(jbuf, "additionalParameters"); + + /***************************************************************************/ + /* Mandatory parameters. */ + /***************************************************************************/ + evel_enc_kv_string(jbuf, "criticality", pcounter->criticality); + evel_enc_kv_string(jbuf, "name", pcounter->name); + evel_enc_kv_string(jbuf, "thresholdCrossed", pcounter->name); + evel_enc_kv_string(jbuf, "value", pcounter->value); + + evel_json_close_object(jbuf); + + 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_threshold_cross(EVEL_JSON_BUFFER * const jbuf, + EVENT_THRESHOLD_CROSS * 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_THRESHOLD_CROSS); + + evel_json_encode_header(jbuf, &event->header); + evel_json_open_named_object(jbuf, "thresholdCrossingAlert"); + + /***************************************************************************/ + /* Mandatory fields */ + /***************************************************************************/ + evel_json_encode_perf_counter(jbuf, &event->additionalParameters); + evel_enc_kv_int(jbuf, "alertAction", event->alertAction); + evel_enc_kv_string(jbuf, "alertDescription", event->alertDescription); + evel_enc_kv_int(jbuf, "alertType", event->alertType); + evel_enc_kv_ull( + jbuf, "collectionTimestamp", event->collectionTimestamp); + evel_enc_kv_int(jbuf, "eventSeverity", event->eventSeverity); + evel_enc_kv_ull( + jbuf, "eventStartTimestamp", event->eventStartTimestamp); + + /***************************************************************************/ + /* Optional fields */ + /***************************************************************************/ + evel_enc_kv_opt_string(jbuf, "alertValue", &event->alertValue); + evel_enc_kv_opt_string(jbuf, "dataCollector", &event->dataCollector); + evel_enc_kv_opt_string(jbuf, "elementType", &event->elementType); + evel_enc_kv_opt_string(jbuf, "interfaceName", &event->interfaceName); + evel_enc_kv_opt_string(jbuf, "networkService", &event->networkService); + evel_enc_kv_opt_string(jbuf, "possibleRootCause", &event->possibleRootCause); + + /***************************************************************************/ + /* 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_info); + 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); + } + } + evel_enc_version(jbuf, + "thresholdCrossingFieldsVersion", + event->major_version, + event->minor_version); + + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} + diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_throttle.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_throttle.c new file mode 100644 index 0000000..6327741 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_throttle.c @@ -0,0 +1,2103 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @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. + * + ****************************************************************************/ + +#define _GNU_SOURCE +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <limits.h> +#include <pthread.h> +#include <search.h> + +#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" + "voiceQuality", + "maxDomain" +}; + +/*****************************************************************************/ +/* 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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_throttle.h b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_throttle.h new file mode 100644 index 0000000..c97b3c3 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_throttle.h @@ -0,0 +1,214 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @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. + * + ****************************************************************************/ + +#ifndef EVEL_THROTTLE_INCLUDED +#define EVEL_THROTTLE_INCLUDED + +#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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_voicequality.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_voicequality.c new file mode 100644 index 0000000..cf2ec87 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_voicequality.c @@ -0,0 +1,640 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * Implementation of EVEL functions relating to the Voice Quality. + *****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#include "evel.h" +#include "evel_internal.h" +#include "evel_throttle.h" + +/**************************************************************************//** + * Create a new voice quality event. + * + * @note The mandatory fields on the Voice Quality 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 Voice Quality has immutable properties. + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc. + * @param calleeSideCodec Callee codec for the call. + * @param callerSideCodec Caller codec for the call. + * @param correlator Constant across all events on this call. + * @param midCallRtcp Base64 encoding of the binary RTCP data + * (excluding Eth/IP/UDP headers). + * @param vendorVnfNameFields Vendor, VNF and VfModule names. + * @returns pointer to the newly manufactured ::EVENT_VOICE_QUALITY. If the + * event is not used (i.e. posted) it must be released using + ::evel_free_voice_quality. + * @retval NULL Failed to create the event. + *****************************************************************************/ +EVENT_VOICE_QUALITY * evel_new_voice_quality(const char* ev_name, const char *ev_id, + const char * const calleeSideCodec, + const char * const callerSideCodec, const char * const correlator, + const char * const midCallRtcp, const char * const vendorName) { + + bool inError = false; + EVENT_VOICE_QUALITY *voiceQuality = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(calleeSideCodec != NULL); + assert(callerSideCodec != NULL); + assert(correlator != NULL); + assert(midCallRtcp != NULL); + assert(vendorName != NULL); + + /***************************************************************************/ + /* Allocate the Voice Quality. */ + /***************************************************************************/ + voiceQuality = malloc(sizeof(EVENT_VOICE_QUALITY)); + + if (voiceQuality == NULL) + { + log_error_state("Out of memory"); + inError = true; + } + + //Only in case of successful allocation initialize data. + if (inError == false) { + memset(voiceQuality, 0, sizeof(EVENT_VOICE_QUALITY)); + EVEL_DEBUG("New Voice Quality is at %lp", voiceQuality); + + /***************************************************************************/ + /* Initialize the header & the fault fields. Optional integer values are */ + /* initialized as 0. */ + /***************************************************************************/ + evel_init_header_nameid(&voiceQuality->header,ev_name,ev_id); + voiceQuality->header.event_domain = EVEL_DOMAIN_VOICE_QUALITY; + voiceQuality->major_version = EVEL_VOICEQ_MAJOR_VERSION; + voiceQuality->minor_version = EVEL_VOICEQ_MINOR_VERSION; + + voiceQuality->calleeSideCodec = strdup(calleeSideCodec); + voiceQuality->callerSideCodec = strdup(callerSideCodec); + voiceQuality->correlator = strdup(correlator); + voiceQuality->midCallRtcp = strdup(midCallRtcp); + evel_init_vendor_field(&voiceQuality->vendorVnfNameFields, vendorName); + dlist_initialize(&voiceQuality->additionalInformation); + voiceQuality->endOfCallVqmSummaries = NULL; + evel_init_option_string(&voiceQuality->phoneNumber); + } + + EVEL_EXIT(); + return voiceQuality; + +} + +/**************************************************************************//** + * Add an additional value name/value pair to the Voice Quality. + * + * 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_voice_quality_addl_info_add(EVENT_VOICE_QUALITY * voiceQ, char * name, char * value) { + VOICE_QUALITY_ADDL_INFO * addlInfo = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(voiceQ != NULL); + assert(voiceQ->header.event_domain == EVEL_DOMAIN_VOICE_QUALITY); + assert(name != NULL); + assert(value != NULL); + + EVEL_DEBUG("Adding name=%s value=%s", name, value); + addlInfo = malloc(sizeof(VOICE_QUALITY_ADDL_INFO)); + assert(addlInfo != NULL); + memset(addlInfo, 0, sizeof(VOICE_QUALITY_ADDL_INFO)); + addlInfo->name = strdup(name); + addlInfo->value = strdup(value); + assert(addlInfo->name != NULL); + assert(addlInfo->value != NULL); + + dlist_push_last(&voiceQ->additionalInformation, addlInfo); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Callee side codec for Call for domain Voice Quality + * + * @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 voiceQuality Pointer to the Voice Quality Event. + * @param calleeCodecForCall The Callee Side Codec to be set. ASCIIZ + * string. The caller does not need to + * preserve the value once the function + * returns. + *****************************************************************************/ +void evel_voice_quality_callee_codec_set(EVENT_VOICE_QUALITY * voiceQuality, + const char * const calleeCodecForCall) { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(voiceQuality != NULL); + assert(voiceQuality->header.event_domain == EVEL_DOMAIN_VOICE_QUALITY); + assert(calleeCodecForCall != NULL); + + voiceQuality->calleeSideCodec = strdup(calleeCodecForCall); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Caller side codec for Call for domain Voice Quality + * + * @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 voiceQuality Pointer to the Voice Quality Event. + * @param callerCodecForCall The Caller Side Codec to be set. ASCIIZ + * string. The caller does not need to + * preserve the value once the function + * returns. + *****************************************************************************/ +void evel_voice_quality_caller_codec_set(EVENT_VOICE_QUALITY * voiceQuality, + const char * const callerCodecForCall) { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(voiceQuality != NULL); + assert(voiceQuality->header.event_domain == EVEL_DOMAIN_VOICE_QUALITY); + assert(callerCodecForCall != NULL); + + voiceQuality->calleeSideCodec = strdup(callerCodecForCall); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the correlator for domain Voice Quality + * + * @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 voiceQuality Pointer to the Voice Quality Event. + * @param correlator The correlator value to be set. ASCIIZ + * string. The caller does not need to + * preserve the value once the function + * returns. + *****************************************************************************/ +void evel_voice_quality_correlator_set(EVENT_VOICE_QUALITY * voiceQuality, + const char * const vCorrelator) { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(voiceQuality != NULL); + assert(voiceQuality->header.event_domain == EVEL_DOMAIN_VOICE_QUALITY); + assert(vCorrelator != NULL); + + voiceQuality->correlator = strdup(vCorrelator); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the RTCP Call Data for domain Voice Quality + * + * @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 voiceQuality Pointer to the Voice Quality Event. + * @param rtcpCallData The RTCP Call Data to be set. ASCIIZ + * string. The caller does not need to + * preserve the value once the function + * returns. + *****************************************************************************/ +void evel_voice_quality_rtcp_data_set(EVENT_VOICE_QUALITY * voiceQuality, + const char * const rtcpCallData) { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(voiceQuality != NULL); + assert(voiceQuality->header.event_domain == EVEL_DOMAIN_VOICE_QUALITY); + assert(rtcpCallData != NULL); + + voiceQuality->midCallRtcp = strdup(rtcpCallData); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Vendor VNF Name fields for domain Voice Quality + * + * @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 voiceQuality Pointer to the Voice Quality Event. + * @param modulename The Vendor, VNF and VfModule names to be set. + * ASCIIZ string. The caller does not need to + * preserve the value once the function + * returns. + *****************************************************************************/ +void evel_voice_quality_vnfmodule_name_set(EVENT_VOICE_QUALITY * voiceQuality, + const char * const module_name) { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(voiceQuality != NULL); + assert(voiceQuality->header.event_domain == EVEL_DOMAIN_VOICE_QUALITY); + assert(module_name != NULL); + + evel_vendor_field_module_set(&voiceQuality->vendorVnfNameFields, module_name); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Vendor VNF Name fields for domain Voice Quality + * + * @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 voiceQuality Pointer to the Voice Quality Event. + * @param modulename The Vendor, VNF and VfModule names to be set. + * ASCIIZ string. The caller does not need to + * preserve the value once the function + * returns. + *****************************************************************************/ +void evel_voice_quality_vnfname_set(EVENT_VOICE_QUALITY * voiceQuality, + const char * const vnfname) { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(voiceQuality != NULL); + assert(voiceQuality->header.event_domain == EVEL_DOMAIN_VOICE_QUALITY); + assert(vnfname != NULL); + + evel_vendor_field_vnfname_set(&voiceQuality->vendorVnfNameFields, vnfname); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Set the Phone Number associated with the Correlator for domain Voice Quality + * + * @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 voiceQuality Pointer to the Voice Quality Event. + * @param calleeCodecForCall The Phone Number to be set. ASCIIZ + * string. The caller does not need to + * preserve the value once the function + * returns. + *****************************************************************************/ +void evel_voice_quality_phone_number_set(EVENT_VOICE_QUALITY * voiceQuality, + const char * const phoneNumber) { + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(voiceQuality != NULL); + assert(voiceQuality->header.event_domain == EVEL_DOMAIN_VOICE_QUALITY); + assert(phoneNumber != NULL); + + evel_set_option_string(&voiceQuality->phoneNumber, phoneNumber, "Phone_Number"); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Add an End of Call Voice Quality Metrices + + * The adjacencyName and endpointDescription is null delimited ASCII string. + * The library takes a copy so the caller does not have to preserve values + * after the function returns. + * + * @param voiceQuality Pointer to the measurement. + * @param adjacencyName Adjacency name + * @param endpointDescription Enumeration: ‘Caller’, ‘Callee’. + * @param endpointJitter Endpoint jitter + * @param endpointRtpOctetsDiscarded Endpoint RTP octets discarded. + * @param endpointRtpOctetsReceived Endpoint RTP octets received. + * @param endpointRtpOctetsSent Endpoint RTP octets sent + * @param endpointRtpPacketsDiscarded Endpoint RTP packets discarded. + * @param endpointRtpPacketsReceived Endpoint RTP packets received. + * @param endpointRtpPacketsSent Endpoint RTP packets sent. + * @param localJitter Local jitter. + * @param localRtpOctetsDiscarded Local RTP octets discarded. + * @param localRtpOctetsReceived Local RTP octets received. + * @param localRtpOctetsSent Local RTP octets sent. + * @param localRtpPacketsDiscarded Local RTP packets discarded. + * @param localRtpPacketsReceived Local RTP packets received. + * @param localRtpPacketsSent Local RTP packets sent. + * @param mosCqe Decimal range from 1 to 5 + * (1 decimal place) + * @param packetsLost No Packets lost + * @param packetLossPercent Calculated percentage packet loss + * @param rFactor rFactor from 0 to 100 + * @param roundTripDelay Round trip delay in milliseconds + *****************************************************************************/ +void evel_voice_quality_end_metrics_add(EVENT_VOICE_QUALITY * voiceQuality, + const char * adjacencyName, EVEL_SERVICE_ENDPOINT_DESC endpointDescription, + int endpointJitter, + int endpointRtpOctetsDiscarded, + int endpointRtpOctetsReceived, + int endpointRtpOctetsSent, + int endpointRtpPacketsDiscarded, + int endpointRtpPacketsReceived, + int endpointRtpPacketsSent, + int localJitter, + int localRtpOctetsDiscarded, + int localRtpOctetsReceived, + int localRtpOctetsSent, + int localRtpPacketsDiscarded, + int localRtpPacketsReceived, + int localRtpPacketsSent, + int mosCqe, + int packetsLost, + int packetLossPercent, + int rFactor, + int roundTripDelay) { + + END_OF_CALL_VOICE_QUALITY_METRICS * vQMetrices = NULL; + EVEL_ENTER(); + + /***************************************************************************/ + /* Check assumptions. */ + /***************************************************************************/ + assert(voiceQuality != NULL); + assert(voiceQuality->header.event_domain == EVEL_DOMAIN_VOICE_QUALITY); + assert(adjacencyName != NULL); + assert(endpointDescription >= 0); + assert(mosCqe >= 1 && mosCqe <= 5); + assert(rFactor >= 0 && rFactor <= 100); + assert(voiceQuality->endOfCallVqmSummaries == NULL); + + /***************************************************************************/ + /* Allocate a container for the value and push onto the list. */ + /***************************************************************************/ + EVEL_DEBUG("Adding adjacencyName=%s endpointDescription=%d", adjacencyName, endpointDescription); + vQMetrices = malloc(sizeof(END_OF_CALL_VOICE_QUALITY_METRICS)); + assert(vQMetrices != NULL); + memset(vQMetrices, 0, sizeof(END_OF_CALL_VOICE_QUALITY_METRICS)); + + vQMetrices->adjacencyName = strdup(adjacencyName); + vQMetrices->endpointDescription = evel_service_endpoint_desc(endpointDescription); + + evel_set_option_int(&vQMetrices->endpointJitter, endpointJitter, "Endpoint jitter"); + evel_set_option_int(&vQMetrices->endpointRtpOctetsDiscarded, endpointRtpOctetsDiscarded, "Endpoint RTP octets discarded"); + evel_set_option_int(&vQMetrices->endpointRtpOctetsReceived, endpointRtpOctetsReceived, "Endpoint RTP octets received"); + evel_set_option_int(&vQMetrices->endpointRtpOctetsSent, endpointRtpOctetsSent, "Endpoint RTP octets sent"); + evel_set_option_int(&vQMetrices->endpointRtpPacketsDiscarded, endpointRtpPacketsDiscarded, "Endpoint RTP packets discarded"); + evel_set_option_int(&vQMetrices->endpointRtpPacketsReceived, endpointRtpPacketsReceived, "Endpoint RTP packets received"); + evel_set_option_int(&vQMetrices->endpointRtpPacketsSent, endpointRtpPacketsSent, "Endpoint RTP packets sent"); + evel_set_option_int(&vQMetrices->localJitter, localJitter, "Local jitter"); + evel_set_option_int(&vQMetrices->localRtpOctetsDiscarded, localRtpOctetsDiscarded, "Local RTP octets discarded"); + evel_set_option_int(&vQMetrices->localRtpOctetsReceived, localRtpOctetsReceived, "Local RTP octets received"); + evel_set_option_int(&vQMetrices->localRtpOctetsSent, localRtpOctetsSent, "Local RTP octets sent"); + evel_set_option_int(&vQMetrices->localRtpPacketsDiscarded, localRtpPacketsDiscarded, "Local RTP packets discarded"); + evel_set_option_int(&vQMetrices->localRtpPacketsReceived, localRtpPacketsReceived, "Local RTP packets received"); + evel_set_option_int(&vQMetrices->localRtpPacketsSent, localRtpPacketsSent, "Local RTP packets sent"); + evel_set_option_int(&vQMetrices->mosCqe, mosCqe, "Decimal range from 1 to 5 (1 decimal place)"); + evel_set_option_int(&vQMetrices->packetsLost, packetsLost, "Packets lost"); + evel_set_option_int(&vQMetrices->packetLossPercent, packetLossPercent, "Calculated percentage packet loss"); + evel_set_option_int(&vQMetrices->rFactor, rFactor, "rFactor "); + evel_set_option_int(&vQMetrices->roundTripDelay, roundTripDelay, "Round trip delay in milliseconds "); + + voiceQuality->endOfCallVqmSummaries = vQMetrices; + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode the Voce Quality in JSON according to AT&T's schema for the voice + * quality 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_voice_quality(EVEL_JSON_BUFFER * jbuf, + EVENT_VOICE_QUALITY * event) +{ + VOICE_QUALITY_ADDL_INFO * addlInfo = NULL; + DLIST_ITEM * addlInfoItem = NULL; + + END_OF_CALL_VOICE_QUALITY_METRICS * vQMetrics = NULL; + DLIST_ITEM * vQMetricsItem = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(event != NULL); + assert(event->header.event_domain == EVEL_DOMAIN_VOICE_QUALITY); + + evel_json_encode_header(jbuf, &event->header); + evel_json_open_named_object(jbuf, "voiceQualityFields"); + + /***************************************************************************/ + /* Mandatory fields. */ + /***************************************************************************/ + evel_enc_kv_string(jbuf, "calleeSideCodec", event->calleeSideCodec); + evel_enc_kv_string(jbuf, "callerSideCodec", event->callerSideCodec); + evel_enc_kv_string(jbuf, "correlator", event->correlator); + evel_enc_kv_string(jbuf, "midCallRtcp", event->midCallRtcp); + evel_json_encode_vendor_field(jbuf, &event->vendorVnfNameFields); + evel_enc_version( + jbuf, "voiceQualityFieldsVersion", event->major_version, event->minor_version); + + /***************************************************************************/ + /* Optional fields. */ + /***************************************************************************/ + evel_enc_kv_opt_string(jbuf, "phoneNumber", &event->phoneNumber); + /***************************************************************************/ + /* Checkpoint, so that we can wind back if all fields are suppressed. */ + /***************************************************************************/ + //additionalInformation for Voice Quality + bool item_added = false; + + evel_json_checkpoint(jbuf); + if (evel_json_open_opt_named_list(jbuf, "additionalInformation")) + { + + addlInfoItem = dlist_get_first(&event->additionalInformation); + while (addlInfoItem != NULL) + { + addlInfo = (VOICE_QUALITY_ADDL_INFO*)addlInfoItem->item; + assert(addlInfo != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "additionalInformation", + addlInfo->name)) + { + evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "name", addlInfo->name); + evel_enc_kv_string(jbuf, "value", addlInfo->value); + evel_json_close_object(jbuf); + item_added = true; + } + addlInfoItem = dlist_get_next(addlInfoItem); + } + 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); + } + } + + //endOfCallVqmSummaries + if( event->endOfCallVqmSummaries != NULL ) + { + evel_json_open_named_object(jbuf, "endOfCallVqmSummaries"); + vQMetrics = event->endOfCallVqmSummaries; + assert(vQMetrics != NULL); + + if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec, + "endOfCallVqmSummaries", vQMetrics->adjacencyName)) + { + evel_enc_kv_string(jbuf, "adjacencyName", vQMetrics->adjacencyName); + evel_enc_kv_string(jbuf, "endpointDescription", vQMetrics->endpointDescription); + evel_enc_kv_opt_int(jbuf, "endpointJitter", &vQMetrics->endpointJitter); + evel_enc_kv_opt_int(jbuf, "endpointRtpOctetsDiscarded", &vQMetrics->endpointRtpOctetsDiscarded); + evel_enc_kv_opt_int(jbuf, "endpointRtpOctetsReceived", &vQMetrics->endpointRtpOctetsReceived); + evel_enc_kv_opt_int(jbuf, "endpointRtpOctetsSent", &vQMetrics->endpointRtpOctetsSent); + evel_enc_kv_opt_int(jbuf, "endpointRtpPacketsDiscarded", &vQMetrics->endpointRtpPacketsDiscarded); + evel_enc_kv_opt_int(jbuf, "endpointRtpPacketsReceived", &vQMetrics->endpointRtpPacketsReceived); + evel_enc_kv_opt_int(jbuf, "endpointRtpPacketsSent", &vQMetrics->endpointRtpPacketsSent); + evel_enc_kv_opt_int(jbuf, "localJitter", &vQMetrics->localJitter); + evel_enc_kv_opt_int(jbuf, "localRtpOctetsDiscarded", &vQMetrics->localRtpOctetsDiscarded); + evel_enc_kv_opt_int(jbuf, "localRtpOctetsReceived", &vQMetrics->localRtpOctetsReceived); + evel_enc_kv_opt_int(jbuf, "localRtpOctetsSent", &vQMetrics->localRtpOctetsSent); + evel_enc_kv_opt_int(jbuf, "localRtpPacketsDiscarded", &vQMetrics->localRtpPacketsDiscarded); + evel_enc_kv_opt_int(jbuf, "localRtpPacketsReceived", &vQMetrics->localRtpPacketsReceived); + evel_enc_kv_opt_int(jbuf, "localRtpPacketsSent", &vQMetrics->localRtpPacketsSent); + evel_enc_kv_opt_int(jbuf, "mosCqe", &vQMetrics->mosCqe); + evel_enc_kv_opt_int(jbuf, "packetsLost", &vQMetrics->packetsLost); + evel_enc_kv_opt_int(jbuf, "packetLossPercent", &vQMetrics->packetLossPercent); + evel_enc_kv_opt_int(jbuf, "rFactor", &vQMetrics->rFactor); + evel_enc_kv_opt_int(jbuf, "roundTripDelay", &vQMetrics->roundTripDelay); + + } + + evel_json_close_object(jbuf); + } + + evel_json_close_object(jbuf); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Free a Voice Quality. + * + * Free off the Voce Quality supplied. Will free all the contained allocated + * memory. + * + * @note It does not free the Voice Quality itself, since that may be part of a + * larger structure. + *****************************************************************************/ +void evel_free_voice_quality(EVENT_VOICE_QUALITY * voiceQuality) { + END_OF_CALL_VOICE_QUALITY_METRICS * vQMetrices = NULL; + VOICE_QUALITY_ADDL_INFO * addlInfo = NULL; + + EVEL_ENTER(); + + /***************************************************************************/ + /* Check preconditions. As an internal API we don't allow freeing NULL */ + /* events as we do on the public API. */ + /***************************************************************************/ + assert(voiceQuality != NULL); + assert(voiceQuality->header.event_domain == EVEL_DOMAIN_VOICE_QUALITY); + + /***************************************************************************/ + /* Free all internal strings then the header itself. */ + /***************************************************************************/ + + //Additional Information + addlInfo = dlist_pop_last(&voiceQuality->additionalInformation); + while (addlInfo != NULL) + { + EVEL_DEBUG("Freeing Additional Info (%s, %s)", + addlInfo->name, + addlInfo->value); + free(addlInfo->name); + free(addlInfo->value); + free(addlInfo); + addlInfo = dlist_pop_last(&voiceQuality->additionalInformation); + } + + //Summary Information + if(voiceQuality->endOfCallVqmSummaries != NULL) + { + vQMetrices = voiceQuality->endOfCallVqmSummaries; + EVEL_DEBUG("Freeing End of Call Voice Measurements Info (%s, %s)", + vQMetrices->adjacencyName, + vQMetrices->endpointDescription); + free(vQMetrices->adjacencyName); + free(vQMetrices); + } + + //Members + free(voiceQuality->calleeSideCodec); + free(voiceQuality->callerSideCodec); + free(voiceQuality->correlator); + free(voiceQuality->midCallRtcp); + evel_free_option_string(&voiceQuality->phoneNumber); + evel_free_event_vendor_field(&voiceQuality->vendorVnfNameFields); + + //header + evel_free_header(&voiceQuality->header); + + EVEL_EXIT(); +} + diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/hashtable.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/hashtable.c new file mode 100644 index 0000000..0e2f764 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/hashtable.c @@ -0,0 +1,222 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * A simple Hashtable. + * + * @note No thread protection so you will need to use appropriate + * synchronization if use spans multiple threads. + * + ****************************************************************************/ + +#include <limits.h> +#include <assert.h> +#include <malloc.h> +#include <string.h> + +#include "hashtable.h" + +/**************************************************************************//** + * Hashtable initialization. + * + * Initialize the list supplied to be empty. + * + * @param size Size of hashtable + + * @returns Hashtable pointer +******************************************************************************/ +/* Create a new hashtable. */ +HASHTABLE_T *ht_create( size_t size ) { + + HASHTABLE_T *hashtable = NULL; + size_t i; + + if( size < 1 ) return NULL; + + /* Allocate the table itself. */ + if( ( hashtable = malloc( sizeof( HASHTABLE_T ) ) ) == NULL ) { + return NULL; + } + + /* Allocate pointers to the head nodes. */ + if( ( hashtable->table = malloc( sizeof( ENTRY_T * ) * size ) ) == NULL ) { + return NULL; + } + for( i = 0; i < size; i++ ) { + hashtable->table[i] = NULL; + } + + hashtable->size = size; + + return hashtable; +} + +/**************************************************************************//** + * Hash a string for a particular hash table. + * + * Initialize the list supplied to be empty. + * + * @param hashtable Pointer to the hashtable + * @param key String + + * @returns hashvalue +******************************************************************************/ +size_t ht_hash( HASHTABLE_T *hashtable, char *key ) +{ + + size_t hash, i; + +#ifdef HASHTABLE_USE_SIMPLE_HASH + for ( hash = i = 0; i < strlen(key); hash = hash << 8, hash += key[ i++ ] ); +#else /* Use: Jenkins' "One At a Time Hash" === Perl "Like" Hashing */ + // http://en.wikipedia.org/wiki/Jenkins_hash_function + for ( hash = i = 0; i < strlen(key); ++i ) { + hash += key[i], hash += ( hash << 10 ), hash ^= ( hash >> 6 ); + } + hash += ( hash << 3 ), hash ^= ( hash >> 11 ), hash += ( hash << 15 ); +#endif + + return hash % hashtable->size; + +} + +/**************************************************************************//** + * Create a key-value pair. + * + * @param key key string + * @param value value string + * + * @returns hashtable entry +******************************************************************************/ +ENTRY_T *ht_newpair( char *key, void *value ) +{ + ENTRY_T *newpair; + + if( ( newpair = malloc( sizeof( ENTRY_T ) ) ) == NULL ) { + return NULL; + } + + if( ( newpair->key = strdup( key ) ) == NULL ) { + return NULL; + } + + if( ( newpair->value = value ) == NULL ) { + return NULL; + } + + newpair->next = NULL; + + return newpair; +} + +/**************************************************************************//** + * Insert a key-value pair into a hash table. + * + * @param key key string + * @param value value string + * + * @returns Nothing +******************************************************************************/ +void ht_set( HASHTABLE_T *hashtable, char *key, void *value ) { + size_t bin = 0; + ENTRY_T *newpair = NULL; + ENTRY_T *next = NULL; + ENTRY_T *last = NULL; + + bin = ht_hash( hashtable, key ); + + next = hashtable->table[ bin ]; + + while( next != NULL && next->key != NULL && strcmp( key, next->key ) > 0 ) { + last = next; + next = next->next; + } + + /* There's already a pair. Let's replace that string. */ + if( next != NULL && next->key != NULL && strcmp( key, next->key ) == 0 ) { + + free( next->value ); + next->value = value ; + + /* Nope, could't find it. Time to grow a pair. */ + } else { + newpair = ht_newpair( key, value ); + + /* We're at the start of the linked list in this bin. */ + if( next == hashtable->table[ bin ] ) { + newpair->next = next; + hashtable->table[ bin ] = newpair; + + /* We're at the end of the linked list in this bin. */ + } else if ( next == NULL ) { + last->next = newpair; + + /* We're in the middle of the list. */ + } else { + newpair->next = next; + last->next = newpair; + } + } +} + +/**************************************************************************//** + * Retrieve a key-value pair from a hash table. + * + * @param key key string + * + * @returns value string +******************************************************************************/ +void *ht_get( HASHTABLE_T *hashtable, char *key ) { + size_t bin = 0; + ENTRY_T *pair; + + bin = ht_hash( hashtable, key ); + + /* Step through the bin, looking for our value. */ + pair = hashtable->table[ bin ]; + while( pair != NULL && pair->key != NULL && strcmp( key, pair->key ) > 0 ) { + pair = pair->next; + } + + /* Did we actually find anything? */ + if( pair == NULL || pair->key == NULL || strcmp( key, pair->key ) != 0 ) { + return NULL; + + } else { + return pair->value; + } + +} + +/* +int main( int argc, char **argv ) { + + HASHTABLE_T *hashtable = ht_create( 65536 ); + + ht_set( hashtable, "key1", "inky" ); + ht_set( hashtable, "key2", "pinky" ); + ht_set( hashtable, "key3", "blinky" ); + ht_set( hashtable, "key4", "floyd" ); + + printf( "%s\n", ht_get( hashtable, "key1" ) ); + printf( "%s\n", ht_get( hashtable, "key2" ) ); + printf( "%s\n", ht_get( hashtable, "key3" ) ); + printf( "%s\n", ht_get( hashtable, "key4" ) ); + + return 0; +} +*/ diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/hashtable.h b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/hashtable.h new file mode 100644 index 0000000..8be17dc --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/hashtable.h @@ -0,0 +1,97 @@ +#ifndef HASHTABLE_INCLUDED +#define HASHTABLE_INCLUDED + +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @file + * A simple hashtable. + * + * @note No thread protection so you will need to use appropriate + * synchronization if use spans multiple threads. +*****************************************************************************/ + +typedef struct entry_s { + char *key; + void *value; + struct entry_s *next; +} ENTRY_T; + +/**************************************************************************//** + * Hashtable structure + *****************************************************************************/ + +typedef struct hashtable_s { + size_t size; + struct entry_s **table; +} HASHTABLE_T; + +/**************************************************************************//** + * Hashtable initialization. + * + * Initialize the list supplied to be empty. + * + * @param size Size of hashtable + + * @returns Hashtable pointer +******************************************************************************/ +/* Create a new hashtable. */ +HASHTABLE_T *ht_create( size_t size ); + +/**************************************************************************//** + * Hash a string for a particular hash table. + * + * Initialize the list supplied to be empty. + * + * @param hashtable Pointer to the hashtable + * @param key String + + * @returns hashvalue +******************************************************************************/ +size_t ht_hash( HASHTABLE_T *hashtable, char *key ); + +/**************************************************************************//** + * Create a key-value pair. + * + * @param key key string + * @param value value string + * + * @returns hashtable entry +******************************************************************************/ +ENTRY_T *ht_newpair( char *key, void *value ); + +/**************************************************************************//** + * Insert a key-value pair into a hash table. + * + * @param key key string + * @param value value string + * + * @returns Nothing +******************************************************************************/ +void ht_set( HASHTABLE_T *hashtable, char *key, void *value ); + +/**************************************************************************//** + * Retrieve a key-value pair from a hash table. + * + * @param key key string + * + * @returns value string +******************************************************************************/ +void *ht_get( HASHTABLE_T *hashtable, char *key ); + +#endif diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/jsmn.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/jsmn.c new file mode 100644 index 0000000..f374a57 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/jsmn.c @@ -0,0 +1,328 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +#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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/jsmn.h b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/jsmn.h new file mode 100644 index 0000000..4ae6d9b --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/jsmn.h @@ -0,0 +1,93 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +#ifndef __JSMN_H_ +#define __JSMN_H_ + +#include <stddef.h> + +#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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/license.md b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/license.md new file mode 100644 index 0000000..95e459a --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/license.md @@ -0,0 +1,81 @@ +# 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 © 2017 AT&T Intellectual Property. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +## 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. + diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/metadata.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/metadata.c new file mode 100644 index 0000000..11fef1b --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/metadata.c @@ -0,0 +1,592 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * Wrap the OpenStack metadata service. + ****************************************************************************/ + +#include <string.h> +#include <assert.h> +#include <malloc.h> + +#include <curl/curl.h> + +#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] = "<NULL>"; + 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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/metadata.h b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/metadata.h new file mode 100644 index 0000000..1ee4409 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/metadata.h @@ -0,0 +1,58 @@ +#ifndef METADATA_INCLUDED +#define METADATA_INCLUDED +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************//** + * @file + * Wrap the OpenStack metadata service. + * + ****************************************************************************/ + +#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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/quickstart.md b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/quickstart.md new file mode 100644 index 0000000..1c735cc --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/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 <domain> + --port <port_number> + [--path <path>] + [--topic <topic>] + [--username <username>] + [--password <password>] + [--https] + [--cycles <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 <cycles> 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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/readme.md b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/readme.md new file mode 100644 index 0000000..3cf5708 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/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 (<em>e.g.</em> +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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/ring_buffer.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/ring_buffer.c new file mode 100644 index 0000000..8080e02 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/ring_buffer.c @@ -0,0 +1,192 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * A ring buffer with multi-threaded synchronization. + * + ****************************************************************************/ + +#include <assert.h> +#include <malloc.h> + +#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/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/ring_buffer.h b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/ring_buffer.h new file mode 100644 index 0000000..1236b78 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/ring_buffer.h @@ -0,0 +1,96 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ + +#ifndef RING_BUFFER_INCLUDED +#define RING_BUFFER_INCLUDED + +/**************************************************************************//** + * @file + * Ring buffer to handle message requests. + * + ****************************************************************************/ + +#include <pthread.h> + +/**************************************************************************//** + * 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 diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_unit/evel_unit.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_unit/evel_unit.c new file mode 100644 index 0000000..f52dc27 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_unit/evel_unit.c @@ -0,0 +1,3484 @@ +/*************************************************************************//** + * + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +/**************************************************************************//** + * @file + * Unit tests for JSON encoding and throttling. + * + * This software is intended to show the essential elements of the library's + * use. + * + ****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <sys/time.h> + +#include "evel.h" +#include "evel_internal.h" +#include "evel_throttle.h" +#include "metadata.h" + +typedef enum { + SERVICE_NONE, + SERVICE_CODEC, + SERVICE_TRANSCODING, + SERVICE_RTCP, + SERVICE_EOC_VQM, + SERVICE_MARKER +} SERVICE_TEST; + +/*****************************************************************************/ +/* Local prototypes. */ +/*****************************************************************************/ +static void test_encode_heartbeat(); +static void test_encode_header_overrides(); +static void test_encode_fault(); +static void test_encode_fault_with_escaping(); +static void test_encode_measurement(); +static void test_encode_mobile_mand(); +static void test_encode_mobile_opts(); +static void test_encode_other(); +static void test_encode_report(); +static void test_encode_service(); +static void test_encode_service_subset(const SERVICE_TEST service_test); +static void test_encode_signaling(); +static void test_encode_state_change(); +static void test_encode_syslog(); +static void test_json_response_junk(); +static void test_json_provide_throttle_state(); +static void test_json_measurement_interval(); +static void test_json_throttle_spec_field(); +static void test_json_throttle_spec_nv_pair(); +static void test_json_throttle_spec_two_domains(); +static void test_json_throttle_spec_bad_command_type(); +static void test_encode_fault_throttled(); +static void test_encode_measurement_throttled(); +static void test_encode_mobile_throttled(); +static void test_encode_other_throttled(); +static void test_encode_report_throttled(); +static void test_encode_service_throttled(); +static void test_encode_signaling_throttled(); +static void test_encode_state_change_throttled(); +static void test_encode_syslog_throttled(); +static void compare_strings(char * expected, + char * actual, + int max_size, + char * description); + +/**************************************************************************//** + * Main function. + * + * Runs all unit test cases, and fails hard on the first failure. + * + * @param[in] argc Argument count. + * @param[in] argv Argument vector - for usage see usage_text. + *****************************************************************************/ +int main(int argc, char ** argv) +{ + assert(argc >= 0); + assert(argv != NULL); + + /***************************************************************************/ + /* Fix our timezone to UTC. */ + /***************************************************************************/ + putenv("TZ=UTC"); + + /***************************************************************************/ + /* Initialize metadata. */ + /***************************************************************************/ + openstack_metadata_initialize(); + + /***************************************************************************/ + /* Minimal initialisation to exercise the encoders. */ + /***************************************************************************/ + functional_role = "UNIT TEST"; + log_initialize(EVEL_LOG_DEBUG, "EVEL"); + + /***************************************************************************/ + /* Test each encoder. */ + /***************************************************************************/ + test_encode_heartbeat(); + test_encode_header_overrides(); + test_encode_fault(); + test_encode_measurement(); + test_encode_mobile_mand(); + test_encode_mobile_opts(); + test_encode_other(); + test_encode_report(); + test_encode_service(); + test_encode_signaling(); + test_encode_state_change(); + test_encode_syslog(); + + /***************************************************************************/ + /* Test JSON Throttle. */ + /***************************************************************************/ + test_json_response_junk(); + test_json_provide_throttle_state(); + test_json_measurement_interval(); + test_json_throttle_spec_field(); + test_json_throttle_spec_nv_pair(); + test_json_throttle_spec_two_domains(); + test_json_throttle_spec_bad_command_type(); + + /***************************************************************************/ + /* Test each encoder with throttling applied. */ + /***************************************************************************/ + test_encode_fault_throttled(); + test_encode_measurement_throttled(); + test_encode_mobile_throttled(); + test_encode_other_throttled(); + test_encode_report_throttled(); + test_encode_service_throttled(); + test_encode_signaling_throttled(); + test_encode_state_change_throttled(); + test_encode_syslog_throttled(); + + /***************************************************************************/ + /* Test character escaping. */ + /***************************************************************************/ + test_encode_fault_with_escaping(); + + printf ("\nAll Tests Passed\n"); + + return 0; +} + +/*****************************************************************************/ +/* We link with this gettimeofday so that we get a fixed result */ +/*****************************************************************************/ +int gettimeofday(struct timeval *tv, + struct timezone *tz __attribute__((unused))) +{ + tv->tv_sec = 1; + tv->tv_usec = 2; + return 0; +} + +void test_encode_heartbeat() +{ + char * expected = + "{\"event\": {" + "\"commonEventHeader\": {" + "\"domain\": \"heartbeat\", " + "\"eventId\": \"121\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 121, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2, " + "\"eventType\": \"Autonomous heartbeat\", " + "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}}}"; + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + + /***************************************************************************/ + /* Test the VM name/uuid once. */ + /***************************************************************************/ + evel_set_next_event_sequence(121); + + EVENT_HEADER * heartbeat = evel_new_heartbeat(); + assert(heartbeat != NULL); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) heartbeat); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Heartbeat"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(heartbeat); +} + +void test_encode_header_overrides() +{ + char * expected = + "{\"event\": {" + "\"commonEventHeader\": {" + "\"domain\": \"heartbeat\", " + "\"eventId\": \"121\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"entity_name_override\", " + "\"sequence\": 121, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1001, " + "\"version\": 1.2, " + "\"eventType\": \"Autonomous heartbeat\", " + "\"reportingEntityId\": \"entity_id_override\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}}}"; + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + + /***************************************************************************/ + /* Test the VM name/uuid once. */ + /***************************************************************************/ + evel_set_next_event_sequence(121); + + EVENT_HEADER * heartbeat = evel_new_heartbeat(); + assert(heartbeat != NULL); + + evel_start_epoch_set(heartbeat, 1001); + evel_last_epoch_set(heartbeat, 1000); + evel_reporting_entity_name_set(heartbeat, "entity_name_override"); + evel_reporting_entity_id_set(heartbeat, "entity_id_override"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) heartbeat); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Heartbeat"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(heartbeat); +} + +void test_encode_fault() +{ + char * expected = + "{\"event\": {" + "\"commonEventHeader\": {" + "\"domain\": \"fault\", " + "\"eventId\": \"122\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 122, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2, " + "\"eventType\": \"Bad things happen...\", " + "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}, " + "\"faultFields\": {" + "\"alarmCondition\": \"My alarm condition\", " + "\"eventSeverity\": \"MAJOR\", " + "\"eventSourceType\": \"other\", " + "\"specificProblem\": \"It broke very badly\", " + "\"eventCategory\": \"link\", " + "\"vfStatus\": \"Active\", " + "\"faultFieldsVersion\": 1.1, " + "\"alarmAdditionalInformation\": [" + "{\"name\": \"name1\", " + "\"value\": \"value1\"}, " + "{\"name\": \"name2\", " + "\"value\": \"value2\"}], " + "\"alarmInterfaceA\": \"My Interface Card\"" + "}}}"; + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + evel_set_next_event_sequence(122); + EVENT_FAULT * fault = evel_new_fault("My alarm condition", + "It broke very badly", + EVEL_PRIORITY_NORMAL, + EVEL_SEVERITY_MAJOR, + EVEL_SOURCE_HOST, + EVEL_VF_STATUS_PREP_TERMINATE); + assert(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"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) fault); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Fault"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(fault); +} + +void test_encode_measurement() +{ + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"measurementsForVfScaling\", " + "\"eventId\": \"123\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 3000, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"entity_name\", " + "\"sequence\": 123, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 2000, " + "\"version\": 1.2, " + "\"eventType\": \"Perf management...\", " + "\"reportingEntityId\": \"entity_id\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}, " + "\"measurementsForVfScalingFields\": " + "{" + "\"measurementInterval\": 5.500000, " + "\"concurrentSessions\": 1, " + "\"configuredEntities\": 2, " + "\"cpuUsageArray\": [" + "{\"cpuIdentifier\": \"cpu1\", " + "\"percentUsage\": 11.110000}, " + "{\"cpuIdentifier\": \"cpu2\", " + "\"percentUsage\": 22.220000}], " + "\"filesystemUsageArray\": [" + "{\"blockConfigured\": 100.110000, " + "\"blockIops\": 33, " + "\"blockUsed\": 100.220000, " + "\"ephemeralConfigured\": 100.110000, " + "\"ephemeralIops\": 44, " + "\"ephemeralUsed\": 200.220000, " + "\"filesystemName\": \"00-11-22\"}, " + "{\"blockConfigured\": 300.110000, " + "\"blockIops\": 55, " + "\"blockUsed\": 300.220000, " + "\"ephemeralConfigured\": 300.110000, " + "\"ephemeralIops\": 66, " + "\"ephemeralUsed\": 400.220000, " + "\"filesystemName\": \"33-44-55\"}], " + "\"latencyDistribution\": [" + "{\"countsInTheBucket\": 20}, " + "{\"lowEndOfLatencyBucket\": 10.000000, " + "\"highEndOfLatencyBucket\": 20.000000, " + "\"countsInTheBucket\": 30}], " + "\"meanRequestLatency\": 4.400000, " + "\"memoryConfigured\": 6.600000, " + "\"memoryUsed\": 3.300000, " + "\"requestRate\": 7, " + "\"vNicUsageArray\": [" + "{" + "\"bytesIn\": 3, " + "\"bytesOut\": 4, " + "\"packetsIn\": 100, " + "\"packetsOut\": 200, " + "\"vNicIdentifier\": \"eth0\"" + "}, " + "{" + "\"bytesIn\": 13, " + "\"bytesOut\": 14, " + "\"packetsIn\": 110, " + "\"packetsOut\": 240, " + "\"vNicIdentifier\": \"eth1\", " + "\"broadcastPacketsIn\": 11, " + "\"broadcastPacketsOut\": 12, " + "\"multicastPacketsIn\": 15, " + "\"multicastPacketsOut\": 16, " + "\"unicastPacketsIn\": 17, " + "\"unicastPacketsOut\": 18" + "}" + "], " + "\"aggregateCpuUsage\": 8.800000, " + "\"numberOfMediaPortsInUse\": 1234, " + "\"vnfcScalingMetric\": 1234.567800, " + "\"errors\": {" + "\"receiveDiscards\": 1, " + "\"receiveErrors\": 0, " + "\"transmitDiscards\": 2, " + "\"transmitErrors\": 1}, " + "\"featureUsageArray\": [" + "{\"featureIdentifier\": \"FeatureA\", " + "\"featureUtilization\": 123}, " + "{\"featureIdentifier\": \"FeatureB\", " + "\"featureUtilization\": 567}], " + "\"codecUsageArray\": [" + "{\"codecIdentifier\": \"G711a\", " + "\"numberInUse\": 91}, " + "{\"codecIdentifier\": \"G729ab\", " + "\"numberInUse\": 92}], " + "\"additionalMeasurements\": [" + "{\"name\": \"Group1\", " + "\"measurements\": [" + "{\"name\": \"Name1\", " + "\"value\": \"Value1\"}]}, " + "{\"name\": \"Group2\", " + "\"measurements\": [" + "{\"name\": \"Name1\", " + "\"value\": \"Value1\"}, " + "{\"name\": \"Name2\", " + "\"value\": \"Value2\"}]}], " + "\"measurementsForVfScalingVersion\": 1.1}}}"; + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_MEASUREMENT * measurement = NULL; + MEASUREMENT_LATENCY_BUCKET * bucket = NULL; + MEASUREMENT_VNIC_PERFORMANCE * vnic_use = NULL; + MEASUREMENT_CPU_USE *cpu_use; + + /***************************************************************************/ + /* Measurement. */ + /***************************************************************************/ + evel_set_next_event_sequence(123); + measurement = evel_new_measurement(5.5); + assert(measurement != NULL); + evel_measurement_type_set(measurement, "Perf management..."); + evel_measurement_conc_sess_set(measurement, 1); + evel_measurement_cfg_ents_set(measurement, 2); + evel_measurement_mean_req_lat_set(measurement, 4.4); + evel_measurement_request_rate_set(measurement, 7); + + cpu_use = evel_measurement_new_cpu_use_add(measurement, "cpu1", 11.11); + evel_measurement_cpu_use_idle_set(cpu_use,22.22); + evel_measurement_cpu_use_interrupt_set(cpu_use,33.33); + evel_measurement_cpu_use_nice_set(cpu_use,44.44); + evel_measurement_cpu_use_softirq_set(cpu_use,55.55); + evel_measurement_cpu_use_steal_set(cpu_use,66.66); + evel_measurement_cpu_use_system_set(cpu_use,77.77); + evel_measurement_cpu_use_usageuser_set(cpu_use,88.88); + evel_measurement_cpu_use_wait_set(cpu_use,99.99); + + cpu_use = evel_measurement_new_cpu_use_add(measurement, "cpu2", 22.22); + evel_measurement_cpu_use_idle_set(cpu_use,12.22); + evel_measurement_cpu_use_interrupt_set(cpu_use,33.33); + evel_measurement_cpu_use_nice_set(cpu_use,44.44); + evel_measurement_cpu_use_softirq_set(cpu_use,55.55); + evel_measurement_cpu_use_steal_set(cpu_use,66.66); + evel_measurement_cpu_use_system_set(cpu_use,77.77); + evel_measurement_cpu_use_usageuser_set(cpu_use,88.88); + evel_measurement_cpu_use_wait_set(cpu_use,19.99); + + + evel_measurement_fsys_use_add(measurement,"00-11-22",100.11, 100.22, 33, + 200.11, 200.22, 44); + evel_measurement_fsys_use_add(measurement,"33-44-55",300.11, 300.22, 55, + 400.11, 400.22, 66); + evel_start_epoch_set(&measurement->header, 2000); + evel_last_epoch_set(&measurement->header, 3000); + evel_reporting_entity_name_set(&measurement->header, "entity_name"); + evel_reporting_entity_id_set(&measurement->header, "entity_id"); + + /***************************************************************************/ + /* Latency Bucket with no optional parameters. */ + /***************************************************************************/ + bucket = evel_new_meas_latency_bucket(20); + evel_meas_latency_bucket_add(measurement, bucket); + + /***************************************************************************/ + /* Latency Bucket with all optional parameters. */ + /***************************************************************************/ + bucket = evel_new_meas_latency_bucket(30); + evel_meas_latency_bucket_low_end_set(bucket, 10.0); + evel_meas_latency_bucket_high_end_set(bucket, 20.0); + evel_meas_latency_bucket_add(measurement, bucket); + + /***************************************************************************/ + /* vNIC Use with no optional parameters. */ + /***************************************************************************/ + vnic_use = evel_new_measurement_vnic_use("eth0", 100, 200, 3, 4); + evel_meas_vnic_use_add(measurement, vnic_use); + + /***************************************************************************/ + /* vNIC Use with all optional parameters. */ + /***************************************************************************/ + vnic_use = evel_new_measurement_vnic_use("eth1", 110, 240, 13, 14); + evel_vnic_use_bcast_pkt_in_set(vnic_use, 11); + evel_vnic_use_bcast_pkt_out_set(vnic_use, 12); + evel_vnic_use_mcast_pkt_in_set(vnic_use, 15); + evel_vnic_use_mcast_pkt_out_set(vnic_use, 16); + evel_vnic_use_ucast_pkt_in_set(vnic_use, 17); + evel_vnic_use_ucast_pkt_out_set(vnic_use, 18); + evel_meas_vnic_use_add(measurement, vnic_use); + + evel_measurement_errors_set(measurement, 1, 0, 2, 1); + + evel_measurement_feature_use_add(measurement, "FeatureA", 123); + evel_measurement_feature_use_add(measurement, "FeatureB", 567); + + evel_measurement_codec_use_add(measurement, "G711a", 91); + evel_measurement_codec_use_add(measurement, "G729ab", 92); + + evel_measurement_media_port_use_set(measurement, 1234); + + evel_measurement_vnfc_scaling_metric_set(measurement, 1234.5678); + + evel_measurement_custom_measurement_add(measurement, + "Group1", "Name1", "Value1"); + evel_measurement_custom_measurement_add(measurement, + "Group2", "Name1", "Value1"); + evel_measurement_custom_measurement_add(measurement, + "Group2", "Name2", "Value2"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) measurement); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Measurement"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(measurement); +} + +void test_encode_mobile_mand() +{ + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"mobileFlow\", " + "\"eventId\": \"1241\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 1241, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2, " + "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}, " + "\"mobileFlowFields\": {" + "\"flowDirection\": \"Outbound\", " + "\"gtpPerFlowMetrics\": {" + "\"avgBitErrorRate\": 12.300000, " + "\"avgPacketDelayVariation\": 3.120000, " + "\"avgPacketLatency\": 100, " + "\"avgReceiveThroughput\": 2100, " + "\"avgTransmitThroughput\": 500, " + "\"flowActivationEpoch\": 1470409421, " + "\"flowActivationMicrosec\": 987, " + "\"flowDeactivationEpoch\": 1470409431, " + "\"flowDeactivationMicrosec\": 11, " + "\"flowDeactivationTime\": \"Fri, 05 Aug 2016 15:03:51 +0000\", " + "\"flowStatus\": \"Working\", " + "\"maxPacketDelayVariation\": 87, " + "\"numActivationFailures\": 3, " + "\"numBitErrors\": 17, " + "\"numBytesReceived\": 123654, " + "\"numBytesTransmitted\": 4561, " + "\"numDroppedPackets\": 0, " + "\"numL7BytesReceived\": 12, " + "\"numL7BytesTransmitted\": 10, " + "\"numLostPackets\": 1, " + "\"numOutOfOrderPackets\": 3, " + "\"numPacketErrors\": 7, " + "\"numPacketsReceivedExclRetrans\": 899, " + "\"numPacketsReceivedInclRetrans\": 901, " + "\"numPacketsTransmittedInclRetrans\": 302, " + "\"numRetries\": 6, " + "\"numTimeouts\": 2, " + "\"numTunneledL7BytesReceived\": 0, " + "\"roundTripTime\": 110, " + "\"timeToFirstByte\": 225" + "}, " + "\"ipProtocolType\": \"TCP\", " + "\"ipVersion\": \"IPv4\", " + "\"otherEndpointIpAddress\": \"2.3.4.1\", " + "\"otherEndpointPort\": 2341, " + "\"reportingEndpointIpAddr\": \"4.2.3.1\", " + "\"reportingEndpointPort\": 4321" + "}}}"; + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + MOBILE_GTP_PER_FLOW_METRICS * metrics = NULL; + EVENT_MOBILE_FLOW * mobile_flow = NULL; + + /***************************************************************************/ + /* Mobile. */ + /***************************************************************************/ + evel_set_next_event_sequence(1241); + + metrics = evel_new_mobile_gtp_flow_metrics(12.3, + 3.12, + 100, + 2100, + 500, + 1470409421, + 987, + 1470409431, + 11, + (time_t)1470409431, + "Working", + 87, + 3, + 17, + 123654, + 4561, + 0, + 12, + 10, + 1, + 3, + 7, + 899, + 901, + 302, + 6, + 2, + 0, + 110, + 225); + assert(metrics != NULL); + mobile_flow = evel_new_mobile_flow("Outbound", + metrics, + "TCP", + "IPv4", + "2.3.4.1", + 2341, + "4.2.3.1", + 4321); + assert(mobile_flow != NULL); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) mobile_flow); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Mobile"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(mobile_flow); +} + +void test_encode_mobile_opts() +{ + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"mobileFlow\", " + "\"eventId\": \"1242\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 1242, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2, " + "\"eventType\": \"Mobile flow...\", " + "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}, " + "\"mobileFlowFields\": {" + "\"flowDirection\": \"Inbound\", " + "\"gtpPerFlowMetrics\": {" + "\"avgBitErrorRate\": 132.000100, " + "\"avgPacketDelayVariation\": 31.200000, " + "\"avgPacketLatency\": 101, " + "\"avgReceiveThroughput\": 2101, " + "\"avgTransmitThroughput\": 501, " + "\"flowActivationEpoch\": 1470409422, " + "\"flowActivationMicrosec\": 988, " + "\"flowDeactivationEpoch\": 1470409432, " + "\"flowDeactivationMicrosec\": 12, " + "\"flowDeactivationTime\": \"Fri, 05 Aug 2016 15:03:52 +0000\", " + "\"flowStatus\": \"Inactive\", " + "\"maxPacketDelayVariation\": 88, " + "\"numActivationFailures\": 4, " + "\"numBitErrors\": 18, " + "\"numBytesReceived\": 123655, " + "\"numBytesTransmitted\": 4562, " + "\"numDroppedPackets\": 1, " + "\"numL7BytesReceived\": 13, " + "\"numL7BytesTransmitted\": 11, " + "\"numLostPackets\": 2, " + "\"numOutOfOrderPackets\": 4, " + "\"numPacketErrors\": 8, " + "\"numPacketsReceivedExclRetrans\": 900, " + "\"numPacketsReceivedInclRetrans\": 902, " + "\"numPacketsTransmittedInclRetrans\": 303, " + "\"numRetries\": 7, " + "\"numTimeouts\": 3, " + "\"numTunneledL7BytesReceived\": 1, " + "\"roundTripTime\": 111, " + "\"timeToFirstByte\": 226, " + "\"ipTosCountList\": [" + "[\"1\", 13], " + "[\"4\", 99], " + "[\"17\", 1]], " + "\"ipTosList\": [\"1\", \"4\", \"17\"], " + "\"tcpFlagList\": [\"CWR\", \"URG\"], " + "\"tcpFlagCountList\": [[\"CWR\", 10], [\"URG\", 121]], " + "\"mobileQciCosList\": [\"conversational\", \"65\"], " + "\"mobileQciCosCountList\": [[\"conversational\", 11], [\"65\", 122]], " + "\"durConnectionFailedStatus\": 12, " + "\"durTunnelFailedStatus\": 13, " + "\"flowActivatedBy\": \"Remote\", " + "\"flowActivationTime\": \"Fri, 05 Aug 2016 15:03:43 +0000\", " + "\"flowDeactivatedBy\": \"Remote\", " + "\"gtpConnectionStatus\": \"Connected\", " + "\"gtpTunnelStatus\": \"Not tunneling\", " + "\"largePacketRtt\": 80, " + "\"largePacketThreshold\": 600.000000, " + "\"maxReceiveBitRate\": 1357924680, " + "\"maxTransmitBitRate\": 235711, " + "\"numGtpEchoFailures\": 1, " + "\"numGtpTunnelErrors\": 4, " + "\"numHttpErrors\": 2" + "}, " + "\"ipProtocolType\": \"UDP\", " + "\"ipVersion\": \"IPv6\", " + "\"otherEndpointIpAddress\": \"2.3.4.2\", " + "\"otherEndpointPort\": 2342, " + "\"reportingEndpointIpAddr\": \"4.2.3.2\", " + "\"reportingEndpointPort\": 4322, " + "\"applicationType\": \"Demo application\", " + "\"appProtocolType\": \"GSM\", " + "\"appProtocolVersion\": \"1\", " + "\"cid\": \"65535\", " + "\"connectionType\": \"S1-U\", " + "\"ecgi\": \"e65535\", " + "\"gtpProtocolType\": \"GTP-U\", " + "\"gtpVersion\": \"1\", " + "\"httpHeader\": \"http://www.something.com\", " + "\"imei\": \"209917614823\", " + "\"imsi\": \"355251/05/850925/8\", " + "\"lac\": \"1\", " + "\"mcc\": \"410\", " + "\"mnc\": \"04\", " + "\"msisdn\": \"6017123456789\", " + "\"otherFunctionalRole\": \"MME\", " + "\"rac\": \"514\", " + "\"radioAccessTechnology\": \"LTE\", " + "\"sac\": \"1\", " + "\"samplingAlgorithm\": 1, " + "\"tac\": \"2099\", " + "\"tunnelId\": \"Tunnel 1\", " + "\"vlanId\": \"15\"" + "}}}"; + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + MOBILE_GTP_PER_FLOW_METRICS * metrics = NULL; + EVENT_MOBILE_FLOW * mobile_flow = NULL; + + /***************************************************************************/ + /* Mobile. */ + /***************************************************************************/ + evel_set_next_event_sequence(1242); + + metrics = evel_new_mobile_gtp_flow_metrics(132.0001, + 31.2, + 101, + 2101, + 501, + 1470409422, + 988, + 1470409432, + 12, + (time_t)1470409432, + "Inactive", + 88, + 4, + 18, + 123655, + 4562, + 1, + 13, + 11, + 2, + 4, + 8, + 900, + 902, + 303, + 7, + 3, + 1, + 111, + 226); + assert(metrics != NULL); + + evel_mobile_gtp_metrics_dur_con_fail_set(metrics, 12); + evel_mobile_gtp_metrics_dur_tun_fail_set(metrics, 13); + evel_mobile_gtp_metrics_act_by_set(metrics, "Remote"); + evel_mobile_gtp_metrics_act_time_set(metrics, (time_t)1470409423); + evel_mobile_gtp_metrics_deact_by_set(metrics, "Remote"); + evel_mobile_gtp_metrics_con_status_set(metrics, "Connected"); + evel_mobile_gtp_metrics_tun_status_set(metrics, "Not tunneling"); + evel_mobile_gtp_metrics_iptos_set(metrics, 1, 13); + evel_mobile_gtp_metrics_iptos_set(metrics, 17, 1); + evel_mobile_gtp_metrics_iptos_set(metrics, 4, 99); + evel_mobile_gtp_metrics_large_pkt_rtt_set(metrics, 80); + evel_mobile_gtp_metrics_large_pkt_thresh_set(metrics, 600.0); + evel_mobile_gtp_metrics_max_rcv_bit_rate_set(metrics, 1357924680); + evel_mobile_gtp_metrics_max_trx_bit_rate_set(metrics, 235711); + evel_mobile_gtp_metrics_num_echo_fail_set(metrics, 1); + evel_mobile_gtp_metrics_num_tun_fail_set(metrics, 4); + evel_mobile_gtp_metrics_num_http_errors_set(metrics, 2); + evel_mobile_gtp_metrics_tcp_flag_count_add(metrics, EVEL_TCP_CWR, 10); + evel_mobile_gtp_metrics_tcp_flag_count_add(metrics, EVEL_TCP_URG, 121); + evel_mobile_gtp_metrics_qci_cos_count_add( + metrics, EVEL_QCI_COS_UMTS_CONVERSATIONAL, 11); + evel_mobile_gtp_metrics_qci_cos_count_add( + metrics, EVEL_QCI_COS_LTE_65, 122); + + mobile_flow = evel_new_mobile_flow("Inbound", + metrics, + "UDP", + "IPv6", + "2.3.4.2", + 2342, + "4.2.3.2", + 4322); + assert(mobile_flow != NULL); + + evel_mobile_flow_type_set(mobile_flow, "Mobile flow..."); + evel_mobile_flow_app_type_set(mobile_flow, "Demo application"); + evel_mobile_flow_app_prot_type_set(mobile_flow, "GSM"); + evel_mobile_flow_app_prot_ver_set(mobile_flow, "1"); + evel_mobile_flow_cid_set(mobile_flow, "65535"); + evel_mobile_flow_con_type_set(mobile_flow, "S1-U"); + evel_mobile_flow_ecgi_set(mobile_flow, "e65535"); + evel_mobile_flow_gtp_prot_type_set(mobile_flow, "GTP-U"); + evel_mobile_flow_gtp_prot_ver_set(mobile_flow, "1"); + evel_mobile_flow_http_header_set(mobile_flow, + "http://www.something.com"); + evel_mobile_flow_imei_set(mobile_flow, "209917614823"); + evel_mobile_flow_imsi_set(mobile_flow, "355251/05/850925/8"); + evel_mobile_flow_lac_set(mobile_flow, "1"); + evel_mobile_flow_mcc_set(mobile_flow, "410"); + evel_mobile_flow_mnc_set(mobile_flow, "04"); + evel_mobile_flow_msisdn_set(mobile_flow, "6017123456789"); + evel_mobile_flow_other_func_role_set(mobile_flow, "MME"); + evel_mobile_flow_rac_set(mobile_flow, "514"); + evel_mobile_flow_radio_acc_tech_set(mobile_flow, "LTE"); + evel_mobile_flow_sac_set(mobile_flow, "1"); + evel_mobile_flow_samp_alg_set(mobile_flow, 1); + evel_mobile_flow_tac_set(mobile_flow, "2099"); + evel_mobile_flow_tunnel_id_set(mobile_flow, "Tunnel 1"); + evel_mobile_flow_vlan_id_set(mobile_flow, "15"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) mobile_flow); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Mobile"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(mobile_flow); +} + +void test_encode_report() +{ + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"measurementsForVfReporting\", " + "\"eventId\": \"125\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 125, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2, " + "\"eventType\": \"Perf reporting...\", " + "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}, " + "\"measurementsForVfReportingFields\": " + "{\"measurementInterval\": 1.100000, " + "\"featureUsageArray\": [" + "{\"featureIdentifier\": \"FeatureA\", " + "\"featureUtilization\": 123}, " + "{\"featureIdentifier\": \"FeatureB\", " + "\"featureUtilization\": 567}], " + "\"additionalMeasurements\": [" + "{\"name\": \"Group1\", " + "\"measurements\": [" + "{\"name\": \"Name1\", " + "\"value\": \"Value1\"}]}, " + "{\"name\": \"Group2\", " + "\"measurements\": [" + "{\"name\": \"Name1\", " + "\"value\": \"Value1\"}, " + "{\"name\": \"Name2\", " + "\"value\": \"Value2\"}]}], " + "\"measurementFieldsVersion\": 1.1}}}"; + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_REPORT * report = NULL; + + /***************************************************************************/ + /* Report. */ + /***************************************************************************/ + evel_set_next_event_sequence(125); + report = evel_new_report(1.1); + assert(report != NULL); + evel_report_type_set(report, "Perf reporting..."); + evel_report_feature_use_add(report, "FeatureA", 123); + evel_report_feature_use_add(report, "FeatureB", 567); + evel_report_custom_measurement_add(report, "Group1", "Name1", "Value1"); + evel_report_custom_measurement_add(report, "Group2", "Name1", "Value1"); + evel_report_custom_measurement_add(report, "Group2", "Name2", "Value2"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) report); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Report"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(report); +} + +void test_encode_service() +{ + test_encode_service_subset(SERVICE_NONE); + test_encode_service_subset(SERVICE_CODEC); + test_encode_service_subset(SERVICE_TRANSCODING); + test_encode_service_subset(SERVICE_RTCP); + test_encode_service_subset(SERVICE_EOC_VQM); + test_encode_service_subset(SERVICE_MARKER); +} + +void test_encode_service_subset(const SERVICE_TEST service_test) +{ + char * expected_start = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"serviceEvents\", " + "\"eventId\": \"2000\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 2000, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2, " + "\"eventType\": \"Service Event\", " + "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}, " + "\"serviceEventsFields\": {" + "\"eventInstanceIdentifier\": " + "{" + "\"vendorId\": \"vendor_x_id\", " + "\"eventId\": \"vendor_x_event_id\", " + "\"productId\": \"vendor_x_product_id\", " + "\"subsystemId\": \"vendor_x_subsystem_id\", " + "\"eventFriendlyName\": \"vendor_x_frieldly_name\"" + "}, " + "\"serviceEventsFieldsVersion\": 1.1, " + "\"correlator\": \"vendor_x_correlator\", " + "\"additionalFields\": [" + "{\"name\": \"Name1\", \"value\": \"Value1\"}, " + "{\"name\": \"Name2\", \"value\": \"Value2\"}, " + "{\"name\": \"Name3\", \"value\": \"Value3\"}, " + "{\"name\": \"Name4\", \"value\": \"Value4\"}]"; + char * expected_codec = + ", " + "\"codecSelected\": {" + "\"codec\": \"PCMA\"" + "}"; + char * expected_transcoding = + ", " + "\"codecSelectedTranscoding\": {" + "\"calleeSideCodec\": \"PCMA\", " + "\"callerSideCodec\": \"G729A\"" + "}"; + char * expected_rtcp = + ", " + "\"midCallRtcp\": {" + "\"rtcpData\": \"some_rtcp_data\"" + "}"; + char * expected_eoc_vqm = + ", " + "\"endOfCallVqmSummaries\": {" + "\"adjacencyName\": \"vendor_x_adjacency\", " + "\"endpointDescription\": \"Caller\", " + "\"endpointJitter\": 66, " + "\"endpointRtpOctetsDiscarded\": 100, " + "\"endpointRtpOctetsReceived\": 200, " + "\"endpointRtpOctetsSent\": 300, " + "\"endpointRtpPacketsDiscarded\": 400, " + "\"endpointRtpPacketsReceived\": 500, " + "\"endpointRtpPacketsSent\": 600, " + "\"localJitter\": 99, " + "\"localRtpOctetsDiscarded\": 150, " + "\"localRtpOctetsReceived\": 250, " + "\"localRtpOctetsSent\": 350, " + "\"localRtpPacketsDiscarded\": 450, " + "\"localRtpPacketsReceived\": 550, " + "\"localRtpPacketsSent\": 650, " + "\"mosCqe\": 12.255000, " + "\"packetsLost\": 157, " + "\"packetLossPercent\": 0.232000, " + "\"rFactor\": 11, " + "\"roundTripDelay\": 15" + "}"; + char * expected_marker = + ", " + "\"marker\": {" + "\"phoneNumber\": \"0888888888\"" + "}"; + char * expected_end = + "}}}"; + + char * expected_middle = NULL; + switch (service_test) + { + case SERVICE_NONE: + expected_middle = ""; + break; + case SERVICE_CODEC: + expected_middle = expected_codec; + break; + case SERVICE_TRANSCODING: + expected_middle = expected_transcoding; + break; + case SERVICE_RTCP: + expected_middle = expected_rtcp; + break; + case SERVICE_EOC_VQM: + expected_middle = expected_eoc_vqm; + break; + case SERVICE_MARKER: + expected_middle = expected_marker; + break; + } + assert(expected_middle != NULL); + + int offset = 0; + char expected[EVEL_MAX_JSON_BODY]; + offset = snprintf(expected + offset, + EVEL_MAX_JSON_BODY - offset, + "%s%s%s", + expected_start, + expected_middle, + expected_end); + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_SGNALING * event = NULL; + evel_set_next_event_sequence(2000); + event = evel_new_signaling("vendor_x_id", + "correlator", "1.0.3.1", "1234", "192.168.1.3","3456"); + assert(event != NULL); + evel_signaling_type_set(event, "Signaling"); + evel_signaling_correlator_set(event, "vendor_x_correlator"); + evel_signaling_vnfmodule_name_set(event, "vendor_x_module"); + evel_signaling_vnfname_set(event, "vendor_x_vnf"); + + switch (service_test) + { + case SERVICE_NONE: + break; + case SERVICE_CODEC: + evel_signaling_addl_info_add(event, "codec", "PCMA"); + break; + case SERVICE_TRANSCODING: + evel_signaling_addl_info_add(event, "calleecodec", "PCMA"); + evel_signaling_addl_info_add(event, "callercodec", "G729A"); + break; + case SERVICE_RTCP: + evel_signaling_addl_info_add(event, "rtcpdata", "abcdefgh"); + break; + case SERVICE_EOC_VQM: + evel_signaling_addl_info_add(event, "adjacency", "vendor_x"); + /*evel_service_adjacency_name_set(event, "vendor_x_adjacency"); + evel_service_endpoint_desc_set(event, EVEL_SERVICE_ENDPOINT_CALLER); + evel_service_endpoint_jitter_set(event, 66); + evel_service_endpoint_rtp_oct_disc_set(event, 100); + evel_service_endpoint_rtp_oct_recv_set(event, 200); + evel_service_endpoint_rtp_oct_sent_set(event, 300); + evel_service_endpoint_rtp_pkt_disc_set(event, 400); + evel_service_endpoint_rtp_pkt_recv_set(event, 500); + evel_service_endpoint_rtp_pkt_sent_set(event, 600); + evel_service_local_jitter_set(event, 99); + evel_service_local_rtp_oct_disc_set(event, 150); + evel_service_local_rtp_oct_recv_set(event, 250); + evel_service_local_rtp_oct_sent_set(event, 350); + evel_service_local_rtp_pkt_disc_set(event, 450); + evel_service_local_rtp_pkt_recv_set(event, 550); + evel_service_local_rtp_pkt_sent_set(event, 650); + evel_service_mos_cqe_set(event, 12.255); + evel_service_packets_lost_set(event, 157); + evel_service_packet_loss_percent_set(event, 0.232); + evel_service_r_factor_set(event, 11); + evel_service_round_trip_delay_set(event, 15);*/ + break; + case SERVICE_MARKER: + evel_signaling_addl_info_add(event, "service_phone", "0888888888"); + break; + } + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) event); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Service"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(event); +} + +void test_encode_signaling() +{ + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"signaling\", " + "\"eventId\": \"2001\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 2001, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2, " + "\"eventType\": \"Signaling\", " + "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}, " + "\"signalingFields\": {" + "\"eventInstanceIdentifier\": " + "{" + "\"vendorId\": \"vendor_x_id\", " + "\"eventId\": \"vendor_x_event_id\", " + "\"productId\": \"vendor_x_product_id\", " + "\"subsystemId\": \"vendor_x_subsystem_id\", " + "\"eventFriendlyName\": \"vendor_x_frieldly_name\"" + "}, " + "\"signalingFieldsVersion\": 1.1, " + "\"correlator\": \"vendor_x_correlator\", " + "\"localIpAddress\": \"1.0.3.1\", " + "\"localPort\": \"1031\", " + "\"remoteIpAddress\": \"5.3.3.0\", " + "\"remotePort\": \"5330\", " + "\"compressedSip\": \"compressed_sip\", " + "\"summarySip\": \"summary_sip\"" + "}}}"; + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_SIGNALING * event = NULL; + evel_set_next_event_sequence(2001); + event = evel_new_signaling("vendor_x_id", + "correlator", "1.0.3.1", "1234", "192.168.1.3","3456"); + assert(event != NULL); + evel_signaling_vnfmodule_name_set(event, "vendor_x_module"); + evel_signaling_vnfname_set(event, "vendor_x_vnf"); + evel_signaling_type_set(event, "Signaling"); + evel_signaling_product_id_set(event, "vendor_x_product_id"); + evel_signaling_subsystem_id_set(event, "vendor_x_subsystem_id"); + evel_signaling_friendly_name_set(event, "vendor_x_frieldly_name"); + evel_signaling_correlator_set(event, "vendor_x_correlator"); + evel_signaling_local_ip_address_set(event, "1.0.3.1"); + evel_signaling_local_port_set(event, "1031"); + evel_signaling_remote_ip_address_set(event, "5.3.3.0"); + evel_signaling_remote_port_set(event, "5330"); + evel_signaling_compressed_sip_set(event, "compressed_sip"); + evel_signaling_summary_sip_set(event, "summary_sip"); + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) event); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Signaling"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(event); +} + +void test_encode_state_change() +{ + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"stateChange\", " + "\"eventId\": \"128\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 128, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2, " + "\"eventType\": \"SC Type\", " + "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}, " + "\"stateChangeFields\": {" + "\"newState\": \"inService\", " + "\"oldState\": \"outOfService\", " + "\"stateInterface\": \"An Interface\", " + "\"additionalFields\": [" + "{\"name\": \"Name1\", " + "\"value\": \"Value1\"}, " + "{\"name\": \"Name2\", " + "\"value\": \"Value2\"}" + "], " + "\"stateChangeFieldsVersion\": 1.1" + "}}}"; + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_STATE_CHANGE * state_change = NULL; + evel_set_next_event_sequence(128); + state_change = evel_new_state_change(EVEL_ENTITY_STATE_IN_SERVICE, + EVEL_ENTITY_STATE_OUT_OF_SERVICE, + "An Interface"); + assert(state_change != NULL); + evel_state_change_type_set(state_change, "SC Type"); + evel_state_change_addl_field_add(state_change, "Name1", "Value1"); + evel_state_change_addl_field_add(state_change, "Name2", "Value2"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) state_change); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "StateChange"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(state_change); +} + +void test_encode_syslog() +{ + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"syslog\", " + "\"eventId\": \"126\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 126, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2, " + "\"eventType\": \"SL Type\", " + "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}, " + "\"syslogFields\": {" + "\"eventSourceType\": \"virtualNetworkFunction\", " + "\"syslogMsg\": \"SL Message\", " + "\"syslogTag\": \"SL Tag\", " + "\"syslogFieldsVersion\": 1.1, " + "\"eventSourceHost\": \"SL Host\", " + "\"syslogFacility\": 6, " + "\"syslogProc\": \"SL Proc\", " + "\"syslogProcId\": 2, " + "\"syslogSData\": \"SL SDATA\", " + "\"syslogVer\": 1" + "}}}"; + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_SYSLOG * syslog = NULL; + evel_set_next_event_sequence(126); + syslog = evel_new_syslog(EVEL_SOURCE_VIRTUAL_NETWORK_FUNCTION, + "SL Message", + "SL Tag"); + assert(syslog != NULL); + evel_syslog_type_set(syslog, "SL Type"); + evel_syslog_event_source_host_set(syslog, "SL Host"); + evel_syslog_facility_set(syslog, EVEL_SYSLOG_FACILITY_LINE_PRINTER); + evel_syslog_proc_set(syslog, "SL Proc"); + evel_syslog_proc_id_set(syslog, 2); + evel_syslog_version_set(syslog, 1); + evel_syslog_s_data_set(syslog, "SL SDATA"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) syslog); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Syslog"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(syslog); +} + +void test_encode_other() +{ + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"other\", " + "\"eventId\": \"129\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 129, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2, " + "\"eventType\": \"Other Type\", " + "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}, " + "\"otherFields\": [" + "{\"name\": \"Other field 1\", " + "\"value\": \"Other value 1\"}, " + "{\"name\": \"Other field 2\", " + "\"value\": \"Other value 2\"}" + "]" + "}}"; + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_OTHER * other = NULL; + evel_set_next_event_sequence(129); + other = evel_new_other(); + assert(other != NULL); + evel_other_type_set(other, "Other Type"); + evel_other_field_add(other, + "Other field 1", + "Other value 1"); + evel_other_field_add(other, + "Other field 2", + "Other value 2"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) other); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Other"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(other); +} + +void compare_strings(char * expected, + char * actual, + int max_size, + char * description) +{ + if (strncmp(expected, actual, max_size) != 0) + { + int diff = 0; + while (diff < max_size) + { + if (expected[diff] != actual[diff]) + { + break; + } + diff++; + } + + printf("Comparison Failure at Offset %d\n\n", diff); + printf("Expected:\n%s\n", expected); + printf("Actual:\n%s\n", actual); + printf("Description: %s\n", description); + assert(0); + } +} + +/**************************************************************************//** + * Copy a json string to a ::MEMORY_CHUNK for testing. + * + * @param chunk The memory chunk. + * @param string The json string. + *****************************************************************************/ +void copy_string_to_chunk(MEMORY_CHUNK * chunk, char * string) +{ + int mem_size; + + /***************************************************************************/ + /* Check preconditions. */ + /***************************************************************************/ + assert(chunk != NULL); + assert(string != NULL); + + mem_size = strlen(string) + 1; + chunk->memory = malloc(mem_size); + memcpy(chunk->memory, string, mem_size); + chunk->size = mem_size; +} + +/**************************************************************************//** + * Copy a json string to a ::MEMORY_CHUNK for testing. + * + * @param json The JSON string. + * @param post Memory chunk to post a response. + *****************************************************************************/ +void handle_json_response(char * json, MEMORY_CHUNK * post) +{ + MEMORY_CHUNK chunk; + post->memory = NULL; + post->size = 0; + copy_string_to_chunk(&chunk, json); + evel_handle_event_response(&chunk, post); + free(chunk.memory); +} + +/**************************************************************************//** + * Test that a non-"commandList" JSON buffer leaves the throttle state off. + *****************************************************************************/ +void test_json_response_junk() +{ + MEMORY_CHUNK post; + int domain; + char * json_junk = + "{" + "\"junk1\": [" + "\"1\", \"2\", \"3\"], " + "\"junk2\": [" + "\"1\", \"2\", \"3\"]" + "}"; + + evel_throttle_initialize(); + handle_json_response(json_junk, &post); + + /***************************************************************************/ + /* Check that all domains are not throttled. */ + /***************************************************************************/ + for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++) + { + assert(evel_get_throttle_spec(domain) == NULL); + } + + /***************************************************************************/ + /* Check that we generated no post. */ + /***************************************************************************/ + assert(post.memory == NULL); + + evel_throttle_terminate(); +} + +char * json_command_list_provide = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"provideThrottlingState\"" + "}" + "}" + "]" + "}"; + +char * json_command_list_fault_clear = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\"" + "}" + "}" + "}" + "]" + "}"; + +char * json_command_list_syslog_clear = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"syslog\"" + "}" + "}" + "}" + "]" + "}"; + +char * expected_throttle_state_normal = + "{" + "\"eventThrottlingState\": {" + "\"eventThrottlingMode\": \"normal\"}" + "}"; + +/**************************************************************************//** + * Test that we can return the default throttling state. + *****************************************************************************/ +void test_json_provide_throttle_state() +{ + MEMORY_CHUNK post; + int domain; + + char * expected_post = expected_throttle_state_normal; + + evel_throttle_initialize(); + handle_json_response(json_command_list_provide, &post); + + /***************************************************************************/ + /* Check that all domains are not throttled. */ + /***************************************************************************/ + for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++) + { + assert(evel_get_throttle_spec(domain) == NULL); + } + + /***************************************************************************/ + /* Check that we generated a throttling specification post. */ + /***************************************************************************/ + assert(post.memory != NULL); + compare_strings(expected_post, post.memory, strlen(expected_post), + "Throttle State Normal"); + free(post.memory); + + evel_throttle_terminate(); +} + +/**************************************************************************//** + * Test the measurement interval handling and API. + *****************************************************************************/ +void test_json_measurement_interval() +{ + MEMORY_CHUNK post; + char * json_command_list_interval_only = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"measurementInterval\": 60" + "}" + "}" + "]" + "}"; + + char * json_command_list_interval_first = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"measurementInterval\": 30, " + "\"commandType\": \"measurementIntervalChange\"" + "}" + "}" + "]" + "}"; + + char * json_command_list_command_first = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"measurementIntervalChange\", " + "\"measurementInterval\": 60" + "}" + "}" + "]" + "}"; + + evel_throttle_initialize(); + assert(evel_get_measurement_interval() == EVEL_MEASUREMENT_INTERVAL_UKNOWN); + + /***************************************************************************/ + /* Check that we're not handling stuff when we shouldn't. */ + /***************************************************************************/ + handle_json_response(json_command_list_interval_only, &post); + assert(post.memory == NULL); + assert(evel_get_measurement_interval() == EVEL_MEASUREMENT_INTERVAL_UKNOWN); + + /***************************************************************************/ + /* Check that we're OK with the interval coming first. */ + /***************************************************************************/ + handle_json_response(json_command_list_interval_first, &post); + assert(post.memory == NULL); + assert(evel_get_measurement_interval() == 30); + + /***************************************************************************/ + /* Check that we're OK with the command type coming first. */ + /***************************************************************************/ + handle_json_response(json_command_list_command_first, &post); + assert(post.memory == NULL); + assert(evel_get_measurement_interval() == 60); + + evel_throttle_terminate(); +} + +/**************************************************************************//** + * Test a single domain, single field suppression. + *****************************************************************************/ +void test_json_throttle_spec_field() +{ + MEMORY_CHUNK post; + int domain; + + char * json_command_list_fault_single = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"]" + "}" + "}" + "}" + "]" + "}"; + + char * json_command_list_fault_double = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [" + "\"alarmInterfaceA\", \"alarmAdditionalInformation\"]" + "}" + "}" + "}" + "]" + "}"; + + char * expected_post_fault_single = + "{" + "\"eventThrottlingState\": {" + "\"eventThrottlingMode\": \"throttled\", " + "\"eventDomainThrottleSpecificationList\": [" + "{" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"]" + "}" + "]" + "}" + "}"; + + char * expected_post_fault_double = + "{" + "\"eventThrottlingState\": {" + "\"eventThrottlingMode\": \"throttled\", " + "\"eventDomainThrottleSpecificationList\": [" + "{" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [" + "\"alarmInterfaceA\", \"alarmAdditionalInformation\"]" + "}" + "]" + "}" + "}"; + + /***************************************************************************/ + /* Initialize and provide a specification with a single fault suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + handle_json_response(json_command_list_fault_single, &post); + + /***************************************************************************/ + /* Check that the FAULT domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL); + for (domain = EVEL_DOMAIN_MEASUREMENT; domain < EVEL_MAX_DOMAINS; domain++) + { + if (domain != EVEL_DOMAIN_FAULT) + { + assert(evel_get_throttle_spec(domain) == NULL); + } + } + assert(post.memory == NULL); + + /***************************************************************************/ + /* Request and verify the throttling state. */ + /***************************************************************************/ + handle_json_response(json_command_list_provide, &post); + assert(post.memory != NULL); + compare_strings(expected_post_fault_single, + post.memory, + strlen(expected_post_fault_single), + "Fault - Single Field"); + free(post.memory); + post.memory = NULL; + + /***************************************************************************/ + /* Update a specification with two faults suppressed. */ + /***************************************************************************/ + handle_json_response(json_command_list_fault_double, &post); + + /***************************************************************************/ + /* Check that the FAULT domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL); + for (domain = EVEL_DOMAIN_MEASUREMENT; domain < EVEL_MAX_DOMAINS; domain++) + { + if (domain != EVEL_DOMAIN_FAULT) + { + assert(evel_get_throttle_spec(domain) == NULL); + } + } + assert(post.memory == NULL); + + /***************************************************************************/ + /* Request and verify the throttling state. */ + /***************************************************************************/ + handle_json_response(json_command_list_provide, &post); + assert(post.memory != NULL); + compare_strings(expected_post_fault_double, + post.memory, + strlen(expected_post_fault_double), + "Fault - Double Field"); + free(post.memory); + post.memory = NULL; + + /***************************************************************************/ + /* Now clear the FAULT domain. */ + /***************************************************************************/ + handle_json_response(json_command_list_fault_clear, &post); + for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++) + { + assert(evel_get_throttle_spec(domain) == NULL); + } + + evel_throttle_terminate(); +} + +/**************************************************************************//** + * Test a single domain, nv_pair suppression. + *****************************************************************************/ +void test_json_throttle_spec_nv_pair() +{ + MEMORY_CHUNK post; + int domain; + + char * json_command_list_fault_pair_single = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}" + "]" + "}" + "}" + "}" + "]" + "}"; + + char * json_command_list_fault_pair_double = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\", \"name2\"]" + "}" + "]" + "}" + "}" + "}" + "]" + "}"; + + char * expected_post_fault_pair_single = + "{" + "\"eventThrottlingState\": {" + "\"eventThrottlingMode\": \"throttled\", " + "\"eventDomainThrottleSpecificationList\": [" + "{" + "\"eventDomain\": \"fault\", " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}" + "]" + "}" + "]" + "}" + "}"; + + char * expected_post_fault_pair_double = + "{" + "\"eventThrottlingState\": {" + "\"eventThrottlingMode\": \"throttled\", " + "\"eventDomainThrottleSpecificationList\": [" + "{" + "\"eventDomain\": \"fault\", " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\", \"name2\"]" + "}" + "]" + "}" + "]" + "}" + "}"; + + /***************************************************************************/ + /* Initialize and provide a specification with a single nvpair with a */ + /* single sub-field suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + handle_json_response(json_command_list_fault_pair_single, &post); + + /***************************************************************************/ + /* Check that the FAULT domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL); + for (domain = EVEL_DOMAIN_MEASUREMENT; domain < EVEL_MAX_DOMAINS; domain++) + { + if (domain != EVEL_DOMAIN_FAULT) + { + assert(evel_get_throttle_spec(domain) == NULL); + } + } + assert(post.memory == NULL); + + /***************************************************************************/ + /* Request and verify the throttling state. */ + /***************************************************************************/ + handle_json_response(json_command_list_provide, &post); + assert(post.memory != NULL); + compare_strings(expected_post_fault_pair_single, + post.memory, + strlen(expected_post_fault_pair_single), + "Fault - Single Pair, Single Field"); + free(post.memory); + post.memory = NULL; + + /***************************************************************************/ + /* Update a specification with a single nvpair with two sub-fields */ + /* suppressed. */ + /***************************************************************************/ + handle_json_response(json_command_list_fault_pair_double, &post); + + /***************************************************************************/ + /* Check that the FAULT domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL); + for (domain = EVEL_DOMAIN_MEASUREMENT; domain < EVEL_MAX_DOMAINS; domain++) + { + if (domain != EVEL_DOMAIN_FAULT) + { + assert(evel_get_throttle_spec(domain) == NULL); + } + } + assert(post.memory == NULL); + + /***************************************************************************/ + /* Request and verify the throttling state. */ + /***************************************************************************/ + handle_json_response(json_command_list_provide, &post); + assert(post.memory != NULL); + compare_strings(expected_post_fault_pair_double, + post.memory, + strlen(expected_post_fault_pair_double), + "Fault - Double Field"); + free(post.memory); + post.memory = NULL; + + /***************************************************************************/ + /* Now clear the FAULT domain. */ + /***************************************************************************/ + handle_json_response(json_command_list_fault_clear, &post); + for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++) + { + assert(evel_get_throttle_spec(domain) == NULL); + } + + evel_throttle_terminate(); +} + +/**************************************************************************//** + * Test two domains, nv_pair suppression. + *****************************************************************************/ +void test_json_throttle_spec_two_domains() +{ + MEMORY_CHUNK post; + int domain; + + char * json_command_list_two_domains = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}]}}}, " + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"syslog\", " + "\"suppressedFieldNames\": [\"syslogProcId\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"additionalFields\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}]}}}" + "]" + "}"; + + char * expected_post_two_domains = + "{" + "\"eventThrottlingState\": {" + "\"eventThrottlingMode\": \"throttled\", " + "\"eventDomainThrottleSpecificationList\": [" + "{" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}]}, " + "{" + "\"eventDomain\": \"syslog\", " + "\"suppressedFieldNames\": [\"syslogProcId\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"additionalFields\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}]}" + "]" + "}" + "}"; + + /***************************************************************************/ + /* Initialize and provide a specification with a single nvpair with a */ + /* single sub-field suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + handle_json_response(json_command_list_two_domains, &post); + + /***************************************************************************/ + /* Check that the FAULT and SYSLOG domains are throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL); + assert(evel_get_throttle_spec(EVEL_DOMAIN_SYSLOG) != NULL); + for (domain = EVEL_DOMAIN_MEASUREMENT; domain < EVEL_MAX_DOMAINS; domain++) + { + if ((domain != EVEL_DOMAIN_FAULT) && (domain != EVEL_DOMAIN_SYSLOG)) + { + assert(evel_get_throttle_spec(domain) == NULL); + } + } + assert(post.memory == NULL); + + /***************************************************************************/ + /* Request and verify the throttling state. */ + /***************************************************************************/ + handle_json_response(json_command_list_provide, &post); + assert(post.memory != NULL); + compare_strings(expected_post_two_domains, + post.memory, + strlen(expected_post_two_domains), + "Fault - Two Domains"); + free(post.memory); + post.memory = NULL; + + /***************************************************************************/ + /* Now clear the FAULT and SYSLOG domains. */ + /***************************************************************************/ + handle_json_response(json_command_list_fault_clear, &post); + assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) == NULL); + assert(evel_get_throttle_spec(EVEL_DOMAIN_SYSLOG) != NULL); + handle_json_response(json_command_list_syslog_clear, &post); + for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++) + { + assert(evel_get_throttle_spec(domain) == NULL); + } + + evel_throttle_terminate(); +} + +/**************************************************************************//** + * Test bad command type. + *****************************************************************************/ +void test_json_throttle_spec_bad_command_type() +{ + MEMORY_CHUNK post; + int domain; + + /***************************************************************************/ + /* Search for "dodgy" in the JSON, and you will see the dodgy bits we're */ + /* handling in these tests. */ + /***************************************************************************/ + #define NUM_BAD_COMMANDS 8 + char * json_command_list_dodgy_command = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"dodgyCommand\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}]}}}" + "]" + "}"; + + char * json_command_list_dodgy_spec = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"dodgyEventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}]}}}" + "]" + "}"; + + char * json_command_list_dodgy_event_domain_key = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"dodgyEventDomainKey\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}]}}}" + "]" + "}"; + + char * json_command_list_dodgy_event_domain = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"dodgyEventDomain\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}]}}}" + "]" + "}"; + + char * json_command_list_dodgy_field_names_key = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}]}}}" + "]" + "}"; + + char * json_command_list_dodgy_pair_names_list_key = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"], " + "\"dodgySuppressedNvPairsListKey\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}]}}}" + "]" + "}"; + + char * json_command_list_dodgy_pair_field_name_key = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"dodgyNvPairFieldNameKey\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}]}}}" + "]" + "}"; + + char * json_command_list_dodgy_pair_names_key = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"dodgySuppressedNvPairNamesKey\": [\"name1\"]" + "}]}}}" + "]" + "}"; + + char * json_command_list_dodgy_depth = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"dodgySuppressedNvPairNamesKey\": " + "[\"name1\", [[[[[[[[]]]]]]]]]" + "}]}}}" + "]" + "}"; + + char * expected_throttle_state_dodgy_field_names_key = + "{" + "\"eventThrottlingState\": {" + "\"eventThrottlingMode\": \"throttled\", " + "\"eventDomainThrottleSpecificationList\": [" + "{" + "\"eventDomain\": \"fault\", " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name1\"]" + "}]}" + "]" + "}" + "}"; + + char * expected_throttle_state_dodgy_pair_names_list_key = + "{" + "\"eventThrottlingState\": {" + "\"eventThrottlingMode\": \"throttled\", " + "\"eventDomainThrottleSpecificationList\": [" + "{" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"]" + "}" + "]" + "}" + "}"; + + char * expected_throttle_state_dodgy_pair_field_name_key = + "{" + "\"eventThrottlingState\": {" + "\"eventThrottlingMode\": \"throttled\", " + "\"eventDomainThrottleSpecificationList\": [" + "{" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"]" + "}" + "]" + "}" + "}"; + + char * expected_throttle_state_dodgy_pair_names_key = + "{" + "\"eventThrottlingState\": {" + "\"eventThrottlingMode\": \"throttled\", " + "\"eventDomainThrottleSpecificationList\": [" + "{" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [\"alarmInterfaceA\"]" + "}" + "]" + "}" + "}"; + + char * json_command_lists[] = { + json_command_list_dodgy_command, + json_command_list_dodgy_spec, + json_command_list_dodgy_event_domain_key, + json_command_list_dodgy_event_domain, + json_command_list_dodgy_depth, + json_command_list_dodgy_field_names_key, + json_command_list_dodgy_pair_names_list_key, + json_command_list_dodgy_pair_field_name_key, + json_command_list_dodgy_pair_names_key + }; + + char * expected_posts[] = { + expected_throttle_state_normal, + expected_throttle_state_normal, + expected_throttle_state_normal, + expected_throttle_state_normal, + expected_throttle_state_normal, + expected_throttle_state_dodgy_field_names_key, + expected_throttle_state_dodgy_pair_names_list_key, + expected_throttle_state_dodgy_pair_field_name_key, + expected_throttle_state_dodgy_pair_names_key + }; + + const int num_commands = + sizeof(json_command_lists) / sizeof(json_command_lists[0]); + const int num_posts = + sizeof(expected_posts) / sizeof(expected_posts[0]); + assert(num_commands == num_posts); + + /***************************************************************************/ + /* Initialize and provide a specification with a single nvpair with a */ + /* single sub-field suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + + int ii; + for (ii = 0; ii < num_commands; ii++) + { + EVEL_DEBUG("Testing commandList[%d] = %s\n", ii, json_command_lists[ii]); + handle_json_response(json_command_lists[ii], &post); + + /*************************************************************************/ + /* Check that throttling is in a normal state - because we ignored the */ + /* command / ..... */ + /*************************************************************************/ + for (domain = EVEL_DOMAIN_MEASUREMENT; domain < EVEL_MAX_DOMAINS; domain++) + { + assert(evel_get_throttle_spec(domain) == NULL); + } + if (expected_posts[ii] == expected_throttle_state_normal) + { + assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) == NULL); + } + else + { + assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL); + } + assert(post.memory == NULL); + + /*************************************************************************/ + /* Request and verify the throttling state. */ + /*************************************************************************/ + handle_json_response(json_command_list_provide, &post); + assert(post.memory != NULL); + compare_strings(expected_posts[ii], + post.memory, + strlen(expected_posts[ii]), + "Throttle State Normal"); + free(post.memory); + post.memory = NULL; + } + + evel_throttle_terminate(); +} + +void test_encode_fault_throttled() +{ + MEMORY_CHUNK post; + + /***************************************************************************/ + /* We also test suppression of the event header parameters here. */ + /***************************************************************************/ + char * json_command_list = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"fault\", " + "\"suppressedFieldNames\": [" + "\"alarmInterfaceA\", " + "\"eventType\", " + "\"reportingEntityId\", " + "\"sourceId\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"alarmAdditionalInformation\", " + "\"suppressedNvPairNames\": [\"name3\", \"name4\"]" + "}]}}}" + "]" + "}"; + + char * expected = + "{\"event\": {" + "\"commonEventHeader\": {" + "\"domain\": \"fault\", " + "\"eventId\": \"122\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 122, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2" + "}, " + "\"faultFields\": {" + "\"alarmCondition\": \"My alarm condition\", " + "\"eventSeverity\": \"MAJOR\", " + "\"eventSourceType\": \"other\", " + "\"specificProblem\": \"It broke very badly\", " + "\"vfStatus\": \"Active\", " + "\"faultFieldsVersion\": 1.1, " + "\"alarmAdditionalInformation\": [" + "{\"name\": \"name1\", " + "\"value\": \"value1\"}, " + "{\"name\": \"name2\", " + "\"value\": \"value2\"}]" + "}}}"; + + /***************************************************************************/ + /* Initialize and provide a specification with a single fault suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + handle_json_response(json_command_list, &post); + + /***************************************************************************/ + /* Check that the domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL); + assert(post.memory == NULL); + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + evel_set_next_event_sequence(122); + EVENT_FAULT * fault = evel_new_fault("My alarm condition", + "It broke very badly", + EVEL_PRIORITY_NORMAL, + EVEL_SEVERITY_MAJOR, + EVEL_SOURCE_HOST, + EVEL_VF_STATUS_PREP_TERMINATE); + assert(fault != NULL); + evel_fault_type_set(fault, "Bad things happen..."); + evel_fault_addl_info_add(fault, "name1", "value1"); + evel_fault_addl_info_add(fault, "name2", "value2"); + + /***************************************************************************/ + /* Suppressed fields. */ + /***************************************************************************/ + evel_fault_interface_set(fault, "My Interface Card"); + evel_fault_addl_info_add(fault, "name3", "value3"); + evel_fault_addl_info_add(fault, "name4", "value4"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) fault); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Fault"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(fault); + evel_throttle_terminate(); +} + +void test_encode_measurement_throttled() +{ + MEMORY_CHUNK post; + + /***************************************************************************/ + /* We also test suppression of the event header parameters here. */ + /***************************************************************************/ + char * json_command_list = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"measurementsForVfScaling\", " + "\"suppressedFieldNames\": [" + "\"errors\", " + "\"vnfcScalingMetric\", " + "\"numberOfMediaPortsInUse\", " + "\"aggregateCpuUsage\", " + "\"requestRate\", " + "\"memoryUsed\", " + "\"memoryConfigured\", " + "\"meanRequestLatency\", " + "\"latencyDistribution\", " + "\"concurrentSessions\", " + "\"configuredEntities\", " + "\"eventType\", " + "\"reportingEntityId\", " + "\"sourceId\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"cpuUsageArray\", " + "\"suppressedNvPairNames\": [\"cpu3\", \"cpu4\"]" + "}, " + "{" + "\"nvPairFieldName\": \"filesystemUsageArray\", " + "\"suppressedNvPairNames\": [\"00-11-22\", \"33-44-55\"]" + "}, " + "{" + "\"nvPairFieldName\": \"vNicUsageArray\", " + "\"suppressedNvPairNames\": [\"eth1\", \"eth0\"]" + "}, " + "{" + "\"nvPairFieldName\": \"featureUsageArray\", " + "\"suppressedNvPairNames\": [\"FeatureB\", \"FeatureC\"]" + "}," + "{" + "\"nvPairFieldName\": \"codecUsageArray\", " + "\"suppressedNvPairNames\": [\"G729ab\"]" + "}," + "{" + "\"nvPairFieldName\": \"additionalMeasurements\", " + "\"suppressedNvPairNames\": [\"Group2\"]" + "}" + "]}}}" + "]" + "}"; + + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"measurementsForVfScaling\", " + "\"eventId\": \"123\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 123, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2" + "}, " + "\"measurementsForVfScalingFields\": " + "{" + "\"measurementInterval\": 5.500000, " + "\"cpuUsageArray\": [" + "{\"cpuIdentifier\": \"cpu1\", " + "\"percentUsage\": 11.110000}, " + "{\"cpuIdentifier\": \"cpu2\", " + "\"percentUsage\": 22.220000}], " + "\"filesystemUsageArray\": [" + "{\"blockConfigured\": 500.110000, " + "\"blockIops\": 77, " + "\"blockUsed\": 500.220000, " + "\"ephemeralConfigured\": 500.110000, " + "\"ephemeralIops\": 88, " + "\"ephemeralUsed\": 600.220000, " + "\"filesystemName\": \"66-77-88\"}], " + "\"featureUsageArray\": [" + "{\"featureIdentifier\": \"FeatureA\", " + "\"featureUtilization\": 123}], " + "\"codecUsageArray\": [" + "{\"codecIdentifier\": \"G711a\", " + "\"numberInUse\": 91}], " + "\"additionalMeasurements\": [" + "{\"name\": \"Group1\", " + "\"measurements\": [" + "{\"name\": \"Name1\", " + "\"value\": \"Value1\"}]}], " + "\"measurementsForVfScalingVersion\": 1.1}}}"; + MEASUREMENT_CPU_USE *cpu_use; + + /***************************************************************************/ + /* Initialize and provide a specification with a single fault suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + handle_json_response(json_command_list, &post); + + /***************************************************************************/ + /* Check that the domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_MEASUREMENT) != NULL); + assert(post.memory == NULL); + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + evel_set_next_event_sequence(123); + EVENT_MEASUREMENT * measurement = evel_new_measurement(5.5); + MEASUREMENT_LATENCY_BUCKET * bucket = NULL; + MEASUREMENT_VNIC_PERFORMANCE * vnic_use = NULL; + assert(measurement != NULL); + + evel_measurement_type_set(measurement, "Perf management..."); + evel_measurement_conc_sess_set(measurement, 1); + evel_measurement_cfg_ents_set(measurement, 2); + evel_measurement_mean_req_lat_set(measurement, 4.4); + evel_measurement_mem_cfg_set(measurement, 6.6); + evel_measurement_mem_used_set(measurement, 3.3); + evel_measurement_request_rate_set(measurement, 7); + + cpu_use = evel_measurement_new_cpu_use_add(measurement, "cpu1", 11.11); + evel_measurement_cpu_use_idle_set(cpu_use,22.22); + evel_measurement_cpu_use_interrupt_set(cpu_use,33.33); + evel_measurement_cpu_use_nice_set(cpu_use,44.44); + evel_measurement_cpu_use_softirq_set(cpu_use,55.55); + evel_measurement_cpu_use_steal_set(cpu_use,66.66); + evel_measurement_cpu_use_system_set(cpu_use,77.77); + evel_measurement_cpu_use_usageuser_set(cpu_use,88.88); + evel_measurement_cpu_use_wait_set(cpu_use,99.99); + + cpu_use = evel_measurement_new_cpu_use_add(measurement, "cpu2", 22.22); + evel_measurement_cpu_use_idle_set(cpu_use,12.22); + evel_measurement_cpu_use_interrupt_set(cpu_use,33.33); + evel_measurement_cpu_use_nice_set(cpu_use,44.44); + evel_measurement_cpu_use_softirq_set(cpu_use,55.55); + evel_measurement_cpu_use_steal_set(cpu_use,66.66); + evel_measurement_cpu_use_system_set(cpu_use,77.77); + evel_measurement_cpu_use_usageuser_set(cpu_use,88.88); + evel_measurement_cpu_use_wait_set(cpu_use,19.99); + + evel_measurement_fsys_use_add(measurement, "00-11-22", + 100.11, 100.22, 33, + 200.11, 200.22, 44); + evel_measurement_fsys_use_add(measurement, "33-44-55", + 300.11, 300.22, 55, + 400.11, 400.22, 66); + evel_measurement_fsys_use_add(measurement, "66-77-88", + 500.11, 500.22, 77, + 600.11, 600.22, 88); + + bucket = evel_new_meas_latency_bucket(20); + evel_meas_latency_bucket_add(measurement, bucket); + + bucket = evel_new_meas_latency_bucket(30); + evel_meas_latency_bucket_low_end_set(bucket, 10.0); + evel_meas_latency_bucket_high_end_set(bucket, 20.0); + evel_meas_latency_bucket_add(measurement, bucket); + + vnic_use = evel_new_measurement_vnic_use("eth0", 100, 200, 3, 4); + evel_vnic_use_bcast_pkt_in_set(vnic_use, 1); + evel_vnic_use_bcast_pkt_out_set(vnic_use, 2); + evel_vnic_use_mcast_pkt_in_set(vnic_use, 5); + evel_vnic_use_mcast_pkt_out_set(vnic_use, 6); + evel_vnic_use_ucast_pkt_in_set(vnic_use, 7); + evel_vnic_use_ucast_pkt_out_set(vnic_use, 8); + evel_meas_vnic_use_add(measurement, vnic_use); + + vnic_use = evel_new_measurement_vnic_use("eth1", 110, 240, 13, 14); + evel_vnic_use_bcast_pkt_in_set(vnic_use, 11); + evel_vnic_use_bcast_pkt_out_set(vnic_use, 12); + evel_vnic_use_mcast_pkt_in_set(vnic_use, 15); + evel_vnic_use_mcast_pkt_out_set(vnic_use, 16); + evel_vnic_use_ucast_pkt_in_set(vnic_use, 17); + evel_vnic_use_ucast_pkt_out_set(vnic_use, 18); + evel_meas_vnic_use_add(measurement, vnic_use); + + evel_measurement_errors_set(measurement, 1, 0, 2, 1); + evel_measurement_feature_use_add(measurement, "FeatureA", 123); + evel_measurement_feature_use_add(measurement, "FeatureB", 567); + evel_measurement_codec_use_add(measurement, "G711a", 91); + evel_measurement_codec_use_add(measurement, "G729ab", 92); + evel_measurement_media_port_use_set(measurement, 1234); + evel_measurement_vnfc_scaling_metric_set(measurement, 1234.5678); + evel_measurement_custom_measurement_add(measurement, + "Group1", "Name1", "Value1"); + evel_measurement_custom_measurement_add(measurement, + "Group2", "Name1", "Value1"); + evel_measurement_custom_measurement_add(measurement, + "Group2", "Name2", "Value2"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) measurement); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Measurement"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(measurement); + evel_throttle_terminate(); +} + +void test_encode_mobile_throttled() +{ + MEMORY_CHUNK post; + + /***************************************************************************/ + /* We also test suppression of the event header parameters here. */ + /***************************************************************************/ + char * json_command_list = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"mobileFlow\", " + "\"suppressedFieldNames\": [" + "\"applicationType\", " + "\"appProtocolType\", " + "\"appProtocolVersion\", " + "\"cid\", " + "\"connectionType\", " + "\"ecgi\", " + "\"gtpProtocolType\", " + "\"gtpVersion\", " + "\"httpHeader\", " + "\"imei\", " + "\"imsi\", " + "\"lac\", " + "\"mcc\", " + "\"mnc\", " + "\"msisdn\", " + "\"otherFunctionalRole\", " + "\"rac\", " + "\"radioAccessTechnology\", " + "\"sac\", " + "\"samplingAlgorithm\", " + "\"tac\", " + "\"tunnelId\", " + "\"vlanId\", " + "\"eventType\", " + "\"reportingEntityId\", " + "\"sourceId\"], " + "\"suppressedNvPairsList\": [" + "]}}}" + "]" + "}"; + + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"mobileFlow\", " + "\"eventId\": \"1242\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 1242, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2" + "}, " + "\"mobileFlowFields\": {" + "\"flowDirection\": \"Inbound\", " + "\"gtpPerFlowMetrics\": {" + "\"avgBitErrorRate\": 132.000100, " + "\"avgPacketDelayVariation\": 31.200000, " + "\"avgPacketLatency\": 101, " + "\"avgReceiveThroughput\": 2101, " + "\"avgTransmitThroughput\": 501, " + "\"flowActivationEpoch\": 1470409422, " + "\"flowActivationMicrosec\": 988, " + "\"flowDeactivationEpoch\": 1470409432, " + "\"flowDeactivationMicrosec\": 12, " + "\"flowDeactivationTime\": \"Fri, 05 Aug 2016 15:03:52 +0000\", " + "\"flowStatus\": \"Inactive\", " + "\"maxPacketDelayVariation\": 88, " + "\"numActivationFailures\": 4, " + "\"numBitErrors\": 18, " + "\"numBytesReceived\": 123655, " + "\"numBytesTransmitted\": 4562, " + "\"numDroppedPackets\": 1, " + "\"numL7BytesReceived\": 13, " + "\"numL7BytesTransmitted\": 11, " + "\"numLostPackets\": 2, " + "\"numOutOfOrderPackets\": 4, " + "\"numPacketErrors\": 8, " + "\"numPacketsReceivedExclRetrans\": 900, " + "\"numPacketsReceivedInclRetrans\": 902, " + "\"numPacketsTransmittedInclRetrans\": 303, " + "\"numRetries\": 7, " + "\"numTimeouts\": 3, " + "\"numTunneledL7BytesReceived\": 1, " + "\"roundTripTime\": 111, " + "\"timeToFirstByte\": 226, " + "\"ipTosCountList\": [" + "[\"1\", 13], " + "[\"4\", 99], " + "[\"17\", 1]], " + "\"ipTosList\": [\"1\", \"4\", \"17\"], " + "\"tcpFlagList\": [\"CWR\", \"URG\"], " + "\"tcpFlagCountList\": [[\"CWR\", 10], [\"URG\", 121]], " + "\"mobileQciCosList\": [\"conversational\", \"65\"], " + "\"mobileQciCosCountList\": [[\"conversational\", 11], [\"65\", 122]], " + "\"durConnectionFailedStatus\": 12, " + "\"durTunnelFailedStatus\": 13, " + "\"flowActivatedBy\": \"Remote\", " + "\"flowActivationTime\": \"Fri, 05 Aug 2016 15:03:43 +0000\", " + "\"flowDeactivatedBy\": \"Remote\", " + "\"gtpConnectionStatus\": \"Connected\", " + "\"gtpTunnelStatus\": \"Not tunneling\", " + "\"largePacketRtt\": 80, " + "\"largePacketThreshold\": 600.000000, " + "\"maxReceiveBitRate\": 1357924680, " + "\"maxTransmitBitRate\": 235711, " + "\"numGtpEchoFailures\": 1, " + "\"numGtpTunnelErrors\": 4, " + "\"numHttpErrors\": 2" + "}, " + "\"ipProtocolType\": \"UDP\", " + "\"ipVersion\": \"IPv6\", " + "\"otherEndpointIpAddress\": \"2.3.4.2\", " + "\"otherEndpointPort\": 2342, " + "\"reportingEndpointIpAddr\": \"4.2.3.2\", " + "\"reportingEndpointPort\": 4322" + "}}}"; + + /***************************************************************************/ + /* Initialize and provide a specification with a single fault suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + handle_json_response(json_command_list, &post); + + /***************************************************************************/ + /* Check that the domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_MOBILE_FLOW) != NULL); + assert(post.memory == NULL); + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + MOBILE_GTP_PER_FLOW_METRICS * metrics = NULL; + EVENT_MOBILE_FLOW * mobile_flow = NULL; + + /***************************************************************************/ + /* Mobile. */ + /***************************************************************************/ + evel_set_next_event_sequence(1242); + + metrics = evel_new_mobile_gtp_flow_metrics(132.0001, + 31.2, + 101, + 2101, + 501, + 1470409422, + 988, + 1470409432, + 12, + (time_t)1470409432, + "Inactive", + 88, + 4, + 18, + 123655, + 4562, + 1, + 13, + 11, + 2, + 4, + 8, + 900, + 902, + 303, + 7, + 3, + 1, + 111, + 226); + assert(metrics != NULL); + + evel_mobile_gtp_metrics_dur_con_fail_set(metrics, 12); + evel_mobile_gtp_metrics_dur_tun_fail_set(metrics, 13); + evel_mobile_gtp_metrics_act_by_set(metrics, "Remote"); + evel_mobile_gtp_metrics_act_time_set(metrics, (time_t)1470409423); + evel_mobile_gtp_metrics_deact_by_set(metrics, "Remote"); + evel_mobile_gtp_metrics_con_status_set(metrics, "Connected"); + evel_mobile_gtp_metrics_tun_status_set(metrics, "Not tunneling"); + evel_mobile_gtp_metrics_iptos_set(metrics, 1, 13); + evel_mobile_gtp_metrics_iptos_set(metrics, 17, 1); + evel_mobile_gtp_metrics_iptos_set(metrics, 4, 99); + evel_mobile_gtp_metrics_large_pkt_rtt_set(metrics, 80); + evel_mobile_gtp_metrics_large_pkt_thresh_set(metrics, 600.0); + evel_mobile_gtp_metrics_max_rcv_bit_rate_set(metrics, 1357924680); + evel_mobile_gtp_metrics_max_trx_bit_rate_set(metrics, 235711); + evel_mobile_gtp_metrics_num_echo_fail_set(metrics, 1); + evel_mobile_gtp_metrics_num_tun_fail_set(metrics, 4); + evel_mobile_gtp_metrics_num_http_errors_set(metrics, 2); + evel_mobile_gtp_metrics_tcp_flag_count_add(metrics, EVEL_TCP_CWR, 10); + evel_mobile_gtp_metrics_tcp_flag_count_add(metrics, EVEL_TCP_URG, 121); + evel_mobile_gtp_metrics_qci_cos_count_add( + metrics, EVEL_QCI_COS_UMTS_CONVERSATIONAL, 11); + evel_mobile_gtp_metrics_qci_cos_count_add( + metrics, EVEL_QCI_COS_LTE_65, 122); + + mobile_flow = evel_new_mobile_flow("Inbound", + metrics, + "UDP", + "IPv6", + "2.3.4.2", + 2342, + "4.2.3.2", + 4322); + assert(mobile_flow != NULL); + + evel_mobile_flow_type_set(mobile_flow, "Mobile flow..."); + evel_mobile_flow_app_type_set(mobile_flow, "Demo application"); + evel_mobile_flow_app_prot_type_set(mobile_flow, "GSM"); + evel_mobile_flow_app_prot_ver_set(mobile_flow, "1"); + evel_mobile_flow_cid_set(mobile_flow, "65535"); + evel_mobile_flow_con_type_set(mobile_flow, "S1-U"); + evel_mobile_flow_ecgi_set(mobile_flow, "e65535"); + evel_mobile_flow_gtp_prot_type_set(mobile_flow, "GTP-U"); + evel_mobile_flow_gtp_prot_ver_set(mobile_flow, "1"); + evel_mobile_flow_http_header_set(mobile_flow, + "http://www.something.com"); + evel_mobile_flow_imei_set(mobile_flow, "209917614823"); + evel_mobile_flow_imsi_set(mobile_flow, "355251/05/850925/8"); + evel_mobile_flow_lac_set(mobile_flow, "1"); + evel_mobile_flow_mcc_set(mobile_flow, "410"); + evel_mobile_flow_mnc_set(mobile_flow, "04"); + evel_mobile_flow_msisdn_set(mobile_flow, "6017123456789"); + evel_mobile_flow_other_func_role_set(mobile_flow, "MME"); + evel_mobile_flow_rac_set(mobile_flow, "514"); + evel_mobile_flow_radio_acc_tech_set(mobile_flow, "LTE"); + evel_mobile_flow_sac_set(mobile_flow, "1"); + evel_mobile_flow_samp_alg_set(mobile_flow, 1); + evel_mobile_flow_tac_set(mobile_flow, "2099"); + evel_mobile_flow_tunnel_id_set(mobile_flow, "Tunnel 1"); + evel_mobile_flow_vlan_id_set(mobile_flow, "15"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) mobile_flow); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Mobile"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(mobile_flow); + evel_throttle_terminate(); +} + +void test_encode_other_throttled() +{ + MEMORY_CHUNK post; + + /***************************************************************************/ + /* We also test suppression of the event header parameters here. */ + /***************************************************************************/ + char * json_command_list = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"other\", " + "\"suppressedFieldNames\": [" + "\"eventType\", " + "\"reportingEntityId\", " + "\"sourceId\"], " + "\"suppressedNvPairsList\": [" + "]}}}" + "]" + "}"; + + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"other\", " + "\"eventId\": \"129\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 129, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2" + "}, " + "\"otherFields\": [" + "{\"name\": \"Other field 1\", " + "\"value\": \"Other value 1\"}, " + "{\"name\": \"Other field 2\", " + "\"value\": \"Other value 2\"}" + "]" + "}}"; + + /***************************************************************************/ + /* Initialize and provide a specification with a single fault suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + handle_json_response(json_command_list, &post); + + /***************************************************************************/ + /* Check that the domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_OTHER) != NULL); + assert(post.memory == NULL); + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_OTHER * other = NULL; + evel_set_next_event_sequence(129); + other = evel_new_other(); + assert(other != NULL); + evel_other_type_set(other, "Other Type"); + evel_other_field_add(other, + "Other field 1", + "Other value 1"); + evel_other_field_add(other, + "Other field 2", + "Other value 2"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) other); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Other"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(other); + evel_throttle_terminate(); +} + +void test_encode_report_throttled() +{ + MEMORY_CHUNK post; + + /***************************************************************************/ + /* We also test suppression of the event header parameters here. */ + /***************************************************************************/ + char * json_command_list = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"report\", " + "\"suppressedFieldNames\": [" + "\"eventType\", " + "\"reportingEntityId\", " + "\"sourceId\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"featureUsageArray\", " + "\"suppressedNvPairNames\": [\"FeatureB\", \"FeatureC\"]" + "}," + "{" + "\"nvPairFieldName\": \"additionalMeasurements\", " + "\"suppressedNvPairNames\": [\"Group2\"]" + "}" + "]}}}" + "]" + "}"; + + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"measurementsForVfReporting\", " + "\"eventId\": \"125\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 125, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2" + "}, " + "\"measurementsForVfReportingFields\": " + "{\"measurementInterval\": 1.100000, " + "\"featureUsageArray\": [" + "{\"featureIdentifier\": \"FeatureA\", " + "\"featureUtilization\": 123}], " + "\"additionalMeasurements\": [" + "{\"name\": \"Group1\", " + "\"measurements\": [" + "{\"name\": \"Name1\", " + "\"value\": \"Value1\"}]}], " + "\"measurementFieldsVersion\": 1.1}}}"; + + /***************************************************************************/ + /* Initialize and provide a specification with a single fault suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + handle_json_response(json_command_list, &post); + + /***************************************************************************/ + /* Check that the domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_REPORT) != NULL); + assert(post.memory == NULL); + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_REPORT * report = NULL; + + /***************************************************************************/ + /* Report. */ + /***************************************************************************/ + evel_set_next_event_sequence(125); + report = evel_new_report(1.1); + assert(report != NULL); + evel_report_type_set(report, "Perf reporting..."); + evel_report_feature_use_add(report, "FeatureA", 123); + evel_report_feature_use_add(report, "FeatureB", 567); + evel_report_custom_measurement_add(report, "Group1", "Name1", "Value1"); + evel_report_custom_measurement_add(report, "Group2", "Name1", "Value1"); + evel_report_custom_measurement_add(report, "Group2", "Name2", "Value2"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) report); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Report"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(report); + evel_throttle_terminate(); +} + +void test_encode_service_throttled() +{ + MEMORY_CHUNK post; + + /***************************************************************************/ + /* We also test suppression of the event header parameters here. */ + /***************************************************************************/ + char * json_command_list = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"serviceEvents\", " + "\"suppressedFieldNames\": [" + "\"eventType\", " + "\"correlator\", " + "\"codecSelected\", " + "\"codecSelectedTranscoding\", " + "\"endOfCallVqmSummaries\", " + "\"midCallRtcp\", " + "\"marker\", " + "\"reportingEntityId\", " + "\"sourceId\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"additionalFields\", " + "\"suppressedNvPairNames\": [\"Name1\", \"Name3\"]" + "}" + "]}}}" + "]" + "}"; + + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"serviceEvents\", " + "\"eventId\": \"2000\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 2000, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2" + "}, " + "\"serviceEventsFields\": {" + "\"eventInstanceIdentifier\": " + "{" + "\"vendorId\": \"vendor_x_id\", " + "\"eventId\": \"vendor_x_event_id\", " + "\"productId\": \"vendor_x_product_id\", " + "\"subsystemId\": \"vendor_x_subsystem_id\", " + "\"eventFriendlyName\": \"vendor_x_frieldly_name\"" + "}, " + "\"serviceEventsFieldsVersion\": 1.1, " + "\"additionalFields\": [" + "{\"name\": \"Name2\", \"value\": \"Value2\"}, " + "{\"name\": \"Name4\", \"value\": \"Value4\"}]" + "}}}"; + + /***************************************************************************/ + /* Initialize and provide a specification with a single fault suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + handle_json_response(json_command_list, &post); + + /***************************************************************************/ + /* Check that the domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_SERVICE) != NULL); + assert(post.memory == NULL); + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_SERVICE * event = NULL; + evel_set_next_event_sequence(2000); + event = evel_new_service("vendor_x_id", "vendor_x_event_id"); + assert(event != NULL); + evel_service_type_set(event, "Service Event"); + evel_service_product_id_set(event, "vendor_x_product_id"); + evel_service_subsystem_id_set(event, "vendor_x_subsystem_id"); + evel_service_friendly_name_set(event, "vendor_x_frieldly_name"); + evel_service_correlator_set(event, "vendor_x_correlator"); + evel_service_codec_set(event, "PCMA"); + evel_service_codec_set(event, "PCMA"); + evel_service_callee_codec_set(event, "PCMA"); + evel_service_caller_codec_set(event, "G729A"); + evel_service_rtcp_data_set(event, "some_rtcp_data"); + evel_service_adjacency_name_set(event, "vendor_x_adjacency"); + evel_service_endpoint_desc_set(event, EVEL_SERVICE_ENDPOINT_CALLER); + evel_service_endpoint_jitter_set(event, 66); + evel_service_endpoint_rtp_oct_disc_set(event, 100); + evel_service_endpoint_rtp_oct_recv_set(event, 200); + evel_service_endpoint_rtp_oct_sent_set(event, 300); + evel_service_endpoint_rtp_pkt_disc_set(event, 400); + evel_service_endpoint_rtp_pkt_recv_set(event, 500); + evel_service_endpoint_rtp_pkt_sent_set(event, 600); + evel_service_local_jitter_set(event, 99); + evel_service_local_rtp_oct_disc_set(event, 150); + evel_service_local_rtp_oct_recv_set(event, 250); + evel_service_local_rtp_oct_sent_set(event, 350); + evel_service_local_rtp_pkt_disc_set(event, 450); + evel_service_local_rtp_pkt_recv_set(event, 550); + evel_service_local_rtp_pkt_sent_set(event, 650); + evel_service_mos_cqe_set(event, 12.255); + evel_service_packets_lost_set(event, 157); + evel_service_packet_loss_percent_set(event, 0.232); + evel_service_r_factor_set(event, 11); + evel_service_round_trip_delay_set(event, 15); + evel_service_phone_number_set(event, "0888888888"); + evel_service_addl_field_add(event, "Name1", "Value1"); + evel_service_addl_field_add(event, "Name2", "Value2"); + evel_service_addl_field_add(event, "Name3", "Value3"); + evel_service_addl_field_add(event, "Name4", "Value4"); + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) event); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Service"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(event); + evel_throttle_terminate(); +} + +void test_encode_signaling_throttled() +{ + MEMORY_CHUNK post; + + /***************************************************************************/ + /* We also test suppression of the event header parameters here. */ + /***************************************************************************/ + char * json_command_list = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"signaling\", " + "\"suppressedFieldNames\": [" + "\"correlator\", " + "\"eventType\", " + "\"reportingEntityId\", " + "\"sourceId\", " + "\"localIpAddress\", " + "\"localPort\", " + "\"remoteIpAddress\", " + "\"remotePort\", " + "\"compressedSip\", " + "\"summarySip\"], " + "\"suppressedNvPairsList\": [" + "]}}}" + "]" + "}"; + + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"signaling\", " + "\"eventId\": \"2001\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 2001, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2" + "}, " + "\"signalingFields\": {" + "\"eventInstanceIdentifier\": " + "{" + "\"vendorId\": \"vendor_x_id\", " + "\"eventId\": \"vendor_x_event_id\", " + "\"productId\": \"vendor_x_product_id\", " + "\"subsystemId\": \"vendor_x_subsystem_id\", " + "\"eventFriendlyName\": \"vendor_x_frieldly_name\"" + "}, " + "\"signalingFieldsVersion\": 1.1" + "}}}"; + + /***************************************************************************/ + /* Initialize and provide a specification with a single fault suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + handle_json_response(json_command_list, &post); + + /***************************************************************************/ + /* Check that the domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_SIGNALING) != NULL); + assert(post.memory == NULL); + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_SIGNALING * event = NULL; + evel_set_next_event_sequence(2001); + event = evel_new_signaling("vendor_x_id", + "correlator", "1.0.3.1", "1234", "192.168.1.3","3456"); + assert(event != NULL); + evel_signaling_vnfmodule_name_set(event, "vendor_x_module"); + evel_signaling_vnfname_set(event, "vendor_x_vnf"); + evel_signaling_type_set(event, "Signaling"); + evel_signaling_product_id_set(event, "vendor_x_product_id"); + evel_signaling_subsystem_id_set(event, "vendor_x_subsystem_id"); + evel_signaling_friendly_name_set(event, "vendor_x_frieldly_name"); + evel_signaling_correlator_set(event, "vendor_x_correlator"); + evel_signaling_local_ip_address_set(event, "1.0.3.1"); + evel_signaling_local_port_set(event, "1031"); + evel_signaling_remote_ip_address_set(event, "5.3.3.0"); + evel_signaling_remote_port_set(event, "5330"); + evel_signaling_compressed_sip_set(event, "compressed_sip"); + evel_signaling_summary_sip_set(event, "summary_sip"); + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) event); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Signaling"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(event); + evel_throttle_terminate(); +} + +void test_encode_state_change_throttled() +{ + MEMORY_CHUNK post; + + /***************************************************************************/ + /* We also test suppression of the event header parameters here. */ + /***************************************************************************/ + char * json_command_list = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"stateChange\", " + "\"suppressedFieldNames\": [" + "\"eventType\", " + "\"reportingEntityId\", " + "\"sourceId\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"additionalFields\", " + "\"suppressedNvPairNames\": [\"Name1\"]" + "}," + "]}}}" + "]" + "}"; + + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"stateChange\", " + "\"eventId\": \"128\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 128, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2" + "}, " + "\"stateChangeFields\": {" + "\"newState\": \"inService\", " + "\"oldState\": \"outOfService\", " + "\"stateInterface\": \"An Interface\", " + "\"additionalFields\": [" + "{\"name\": \"Name2\", " + "\"value\": \"Value2\"}" + "], " + "\"stateChangeFieldsVersion\": 1.1" + "}}}"; + + /***************************************************************************/ + /* Initialize and provide a specification with a single fault suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + handle_json_response(json_command_list, &post); + + /***************************************************************************/ + /* Check that the domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_STATE_CHANGE) != NULL); + assert(post.memory == NULL); + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_STATE_CHANGE * state_change = NULL; + evel_set_next_event_sequence(128); + state_change = evel_new_state_change(EVEL_ENTITY_STATE_IN_SERVICE, + EVEL_ENTITY_STATE_OUT_OF_SERVICE, + "An Interface"); + assert(state_change != NULL); + evel_state_change_type_set(state_change, "SC Type"); + evel_state_change_addl_field_add(state_change, "Name1", "Value1"); + evel_state_change_addl_field_add(state_change, "Name2", "Value2"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) state_change); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "StateChange"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(state_change); + evel_throttle_terminate(); +} + +void test_encode_syslog_throttled() +{ + MEMORY_CHUNK post; + + /***************************************************************************/ + /* We also test suppression of the event header parameters here. */ + /***************************************************************************/ + char * json_command_list = + "{" + "\"commandList\": [" + "{" + "\"command\": {" + "\"commandType\": \"throttlingSpecification\", " + "\"eventDomainThrottleSpecification\": {" + "\"eventDomain\": \"syslog\", " + "\"suppressedFieldNames\": [" + "\"eventSourceHost\", " + "\"syslogFacility\", " + "\"syslogProc\", " + "\"syslogProcId\", " + "\"syslogSData\", " + "\"syslogVer\", " + "\"eventType\", " + "\"reportingEntityId\", " + "\"sourceId\"], " + "\"suppressedNvPairsList\": [" + "{" + "\"nvPairFieldName\": \"additionalFields\", " + "\"suppressedNvPairNames\": [\"Name2\"]" + "}," + "]}}}" + "]" + "}"; + + char * expected = + "{\"event\": " + "{\"commonEventHeader\": {" + "\"domain\": \"syslog\", " + "\"eventId\": \"126\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 126, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2" + "}, " + "\"syslogFields\": {" + "\"eventSourceType\": \"virtualNetworkFunction\", " + "\"syslogMsg\": \"SL Message\", " + "\"syslogTag\": \"SL Tag\", " + "\"syslogFieldsVersion\": 1.1, " + "\"additionalFields\": [" + "{\"name\": \"Name1\", " + "\"value\": \"Value1\"}" + "]" + "}}}"; + + /***************************************************************************/ + /* Initialize and provide a specification with a single fault suppressed. */ + /***************************************************************************/ + evel_throttle_initialize(); + handle_json_response(json_command_list, &post); + + /***************************************************************************/ + /* Check that the domain is throttled. */ + /***************************************************************************/ + assert(evel_get_throttle_spec(EVEL_DOMAIN_SYSLOG) != NULL); + assert(post.memory == NULL); + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + EVENT_SYSLOG * syslog = NULL; + evel_set_next_event_sequence(126); + syslog = evel_new_syslog(EVEL_SOURCE_VIRTUAL_NETWORK_FUNCTION, + "SL Message", + "SL Tag"); + assert(syslog != NULL); + evel_syslog_type_set(syslog, "SL Type"); + evel_syslog_event_source_host_set(syslog, "SL Host"); + evel_syslog_facility_set(syslog, EVEL_SYSLOG_FACILITY_LINE_PRINTER); + evel_syslog_proc_set(syslog, "SL Proc"); + evel_syslog_proc_id_set(syslog, 2); + evel_syslog_version_set(syslog, 1); + evel_syslog_s_data_set(syslog, "SL SDATA"); + evel_syslog_addl_field_add(syslog, "Name1", "Value1"); + evel_syslog_addl_field_add(syslog, "Name2", "Value2"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) syslog); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Syslog"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(syslog); + evel_throttle_terminate(); +} + +void test_encode_fault_with_escaping() +{ + char * expected = + "{\"event\": {" + "\"commonEventHeader\": {" + "\"domain\": \"fault\", " + "\"eventId\": \"122\", " + "\"functionalRole\": \"UNIT TEST\", " + "\"lastEpochMicrosec\": 1000002, " + "\"priority\": \"Normal\", " + "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", " + "\"sequence\": 122, " + "\"sourceName\": \"Dummy VM name - No Metadata available\", " + "\"startEpochMicrosec\": 1000002, " + "\"version\": 1.2, " + "\"eventType\": \"Bad things happen...\\\\\", " + "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", " + "\"sourceId\": \"Dummy VM UUID - No Metadata available\"" + "}, " + "\"faultFields\": {" + "\"alarmCondition\": \"My alarm condition\", " + "\"eventSeverity\": \"MAJOR\", " + "\"eventSourceType\": \"other\", " + "\"specificProblem\": \"It broke \\\"very\\\" badly\", " + "\"vfStatus\": \"Active\", " + "\"faultFieldsVersion\": 1.1, " + "\"alarmAdditionalInformation\": [" + "{\"name\": \"name1\", " + "\"value\": \"value1\"}, " + "{\"name\": \"name2\", " + "\"value\": \"value2\"}], " + "\"alarmInterfaceA\": \"My Interface Card\"" + "}}}"; + + size_t json_size = 0; + char json_body[EVEL_MAX_JSON_BODY]; + evel_set_next_event_sequence(122); + EVENT_FAULT * fault = evel_new_fault("My alarm condition", + "It broke \"very\" badly", + EVEL_PRIORITY_NORMAL, + EVEL_SEVERITY_MAJOR, + EVEL_SOURCE_HOST, + EVEL_VF_STATUS_PREP_TERMINATE); + assert(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"); + + json_size = evel_json_encode_event( + json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) fault); + compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Fault"); + assert((json_size == strlen(json_body)) && "Bad size returned"); + + evel_free_event(fault); +} diff --git a/veslibrary/ves_clibrary/evel/evel-library/docs/source/evel/README b/veslibrary/ves_clibrary/evel/evel-library/docs/source/evel/README new file mode 100644 index 0000000..89e7a3a --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/docs/source/evel/README @@ -0,0 +1 @@ +Generated source code documentation.
\ No newline at end of file diff --git a/veslibrary/ves_clibrary/evel/evel-library/libs/x86_64/README b/veslibrary/ves_clibrary/evel/evel-library/libs/x86_64/README new file mode 100644 index 0000000..760fdc1 --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/libs/x86_64/README @@ -0,0 +1 @@ +Generated libraries.
\ No newline at end of file diff --git a/veslibrary/ves_clibrary/evel/evel-library/output/x86_64/README b/veslibrary/ves_clibrary/evel/evel-library/output/x86_64/README new file mode 100644 index 0000000..d1c9f1f --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/output/x86_64/README @@ -0,0 +1 @@ +Generated executables.
\ No newline at end of file diff --git a/veslibrary/ves_clibrary/evel/evel-library/readme.md b/veslibrary/ves_clibrary/evel/evel-library/readme.md new file mode 100644 index 0000000..65ce4ef --- /dev/null +++ b/veslibrary/ves_clibrary/evel/evel-library/readme.md @@ -0,0 +1,28 @@ +# ECOMP Vendor Event Listener Library + +This project contains a C library that supports interfacing to AT&T's ECOMP +Vendor Event Listener. For an overview of ECOMP, see the +[ECOMP White Paper](http://att.com/ECOMP). + +Developed in 2016 for AT&T by: + * Alok Gupta (https://github.com/ag1367) + * Paul Potochniak (https://github.com/pp8491) + * Gayathri Patrachari(https://github.com/gp2421) + +Current Maintainers: + * Alok Gupta (https://github.com/ag1367) + * Paul Potochniak (https://github.com/pp8491) + * Gayathri Patrachari(https://github.com/gp2421) + +# Installation + +For installation instructions, clone this repo and load the +[installation guide](./docs/source/evel/html/quickstart.html) in your web browser. + +Full source-code documentation is included with the code and can be built from +the included Makefile. See the [readme file](./code/evel_library/readme.md). + +# Use + +Clone this repo and load the [user guide](./docs/source/evel/html/index.html) +in your web browser.
\ No newline at end of file |