From f7b9695ecc2b3ec3fff0af300f0588ead4b7ba0f Mon Sep 17 00:00:00 2001 From: "E. Scott Daniels" Date: Wed, 29 Apr 2020 10:07:53 -0400 Subject: [PATCH] Phase 2 of image generation prep This change: - deletes some of the unnecessary framework files which were imported at repo create time. - adds docs for RTD - Adds CMake files to build (easier for CI) - Tweaks the docker file to build using cmake Issue-ID: RIC-349 Signed-off-by: E. Scott Daniels Change-Id: I94202642764d4b4c0c3555a37dc8b36f4c009f3f --- .gitignore | 3 + .readthedocs.yaml | 21 ++ CMakeLists.txt | 217 ++---------- Dockerfile | 21 +- build_rmr.sh | 23 -- container-tag.yaml | 3 + docs/.gitignore | 2 + docs/_static/logo.png | Bin 0 -> 43935 bytes docs/conf.py | 6 + docs/conf.yaml | 3 + docs/favicon.ico | Bin 0 -> 15086 bytes docs/index.rst | 20 ++ docs/rel-notes.rst | 16 + docs/requirements-docs.txt | 5 + docs/user-guide.rst | 21 ++ src/messaging/README | 47 --- src/messaging/callback.cpp | 58 ---- src/messaging/callback.hpp | 52 --- src/messaging/default_cb.cpp | 54 --- src/messaging/default_cb.hpp | 39 --- src/messaging/message.cpp | 419 ----------------------- src/messaging/message.hpp | 110 ------ src/messaging/messenger.cpp | 279 --------------- src/messaging/messenger.hpp | 82 ----- src/messaging/msg_component.hpp | 57 --- src/{messaging => ts_xapp}/CMakeLists.txt | 36 +- src/{xapp/CMakeLists.txt => ts_xapp/Makefile} | 35 +- examples/ts_xapp.cpp~ => src/ts_xapp/ts_xapp.cpp | 6 +- src/xapp/README | 27 -- src/xapp/xapp.cpp | 100 ------ src/xapp/xapp.hpp | 63 ---- test/rmr_em.c | 255 -------------- test/unit_test.cpp | 302 ---------------- test/unit_test.sh | 10 +- tox.ini | 37 ++ 35 files changed, 210 insertions(+), 2219 deletions(-) create mode 100644 .gitignore create mode 100644 .readthedocs.yaml delete mode 100755 build_rmr.sh create mode 100644 container-tag.yaml create mode 100644 docs/.gitignore create mode 100644 docs/_static/logo.png create mode 100644 docs/conf.py create mode 100644 docs/conf.yaml create mode 100644 docs/favicon.ico create mode 100644 docs/index.rst create mode 100644 docs/rel-notes.rst create mode 100644 docs/requirements-docs.txt create mode 100644 docs/user-guide.rst delete mode 100644 src/messaging/README delete mode 100644 src/messaging/callback.cpp delete mode 100644 src/messaging/callback.hpp delete mode 100644 src/messaging/default_cb.cpp delete mode 100644 src/messaging/default_cb.hpp delete mode 100644 src/messaging/message.cpp delete mode 100644 src/messaging/message.hpp delete mode 100644 src/messaging/messenger.cpp delete mode 100644 src/messaging/messenger.hpp delete mode 100644 src/messaging/msg_component.hpp rename src/{messaging => ts_xapp}/CMakeLists.txt (53%) rename src/{xapp/CMakeLists.txt => ts_xapp/Makefile} (58%) rename examples/ts_xapp.cpp~ => src/ts_xapp/ts_xapp.cpp (98%) delete mode 100644 src/xapp/README delete mode 100644 src/xapp/xapp.cpp delete mode 100644 src/xapp/xapp.hpp delete mode 100644 test/rmr_em.c delete mode 100644 test/unit_test.cpp create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf365a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.build/ +*- +*~ diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..d0d12e3 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,21 @@ +--- +# .readthedocs.yml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details +# Required +version: 2 + +formats: + - htmlzip + +build: + image: latest + +python: + version: 3.7 + install: + - requirements: docs/requirements-docs.txt + +sphinx: + configuration: docs/conf.py + diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e65e5f..63a70b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,7 @@ #================================================================================== -# Copyright (c) 2019 Nokia -# Copyright (c) 2018-2019 AT&T Intellectual Property. +# Copyright (c) 2020 AT&T Intellectual Property. # -# Licensed under the Apache License, Version 2.0 (the "License"); +# 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 # @@ -19,26 +18,26 @@ # This CMake definition supports several -D command line options: # # -DDEBUG=n Enable debugging level n -# -DDEV_PKG=1 Development package configuration -# -DBUILD_DOC=1 Man pages generated -# -DPRESERVE_PTYPE=1 Do not change the processor type when naming deb packages # -DGPROF=1 Enable profiling compile time flags -# -DMAN_PREFIX= Supply a path where man pages are installed (default: /usr/share/man) +# +# Building the binaries in this project should be as easy as running the +# following command in this directory: +# rm -fr .build +# make .build +# cd .build +# cmake .. [-DGPROF=1] [-DDEBUG=1] +# make test [install] ARGS=-V +# project( ricxfcpp ) -cmake_minimum_required( VERSION 3.5 ) +cmake_minimum_required( VERSION 3.14 ) -set( major_version "0" ) # should be automatically populated from git tag later, but until CI process sets a tag we use this -set( minor_version "1" ) -set( patch_level "2" ) +set( major_version "1" ) # until CI supports auto tagging; must hard set +set( minor_version "0" ) +set( patch_level "0" ) set( install_root "${CMAKE_INSTALL_PREFIX}" ) -set( install_inc "include/ricxfcpp" ) -if( MAN_PREFIX ) - set( install_man ${MAN_PREFIX} ) # is there a cmake var for this -- can't find one -else() - set( install_man "/usr/share/man" ) # this needs to be fixed so it's not hard coded -endif() +set( install_inc "/usr/local/include" ) # Must use GNUInstallDirs to install libraries into correct # locations on all platforms. @@ -52,37 +51,6 @@ if( NOT CMAKE_INSTALL_LIBDIR ) endif() set( install_lib "${CMAKE_INSTALL_LIBDIR}" ) -message( "+++ ricxfcpp library install target directory: ${install_lib}" ) - -# ---------------- extract some things from git ------------------------------ - -# commit id for the version string -execute_process( - COMMAND bash -c "git rev-parse --short HEAD|awk '{printf\"%s\", $0}'" - OUTPUT_VARIABLE git_id -) - -# version information for library names and version string -execute_process( - COMMAND bash -c "git describe --tags --abbrev=0 HEAD 2>/dev/null | awk -v tag=0.0.4095 ' { tag=$1 } END{ print tag suffix }'|sed 's/\\./;/g' " - OUTPUT_VARIABLE mmp_version_str - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE -) -message( "+++ mmp version from tag: '${mmp_version_str}'" ) - -# extra indicator to show that the build was based on modified file(s) and not the true commit -# (no hope of reproducing the exact library for debugging). Used only for the internal version -# string. -execute_process( - COMMAND bash -c "git diff --shortstat|awk -v fmt=%s -v r=-rotten '{ s=r } END { printf( fmt, s ) }'" - OUTPUT_VARIABLE spoiled_str -) - -# uncomment these lines once CI starts adding a tag on merge -#set( mmp_version ${mmp_version_str} ) -#list( GET mmp_version 0 major_version ) -#list( GET mmp_version 1 minor_version ) -#list( GET mmp_version 2 patch_level ) if( DEBUG ) # if set, we'll set debugging on in the compile set( debugging ${DEBUG} ) @@ -94,6 +62,14 @@ endif() unset( DEBUG CACHE ) # we don't want this to persist +# ---------------- extract some things from git ------------------------------ + +# commit id for the version string +execute_process( + COMMAND bash -c "git rev-parse --short HEAD|awk '{printf\"%s\", $0}'" + OUTPUT_VARIABLE git_id +) + # define constants used in the version string, debugging, etc. add_definitions( -DGIT_ID=${git_id} @@ -103,101 +79,23 @@ add_definitions( -DDEBUG=${debugging} ) -# ---------------- suss out pkg gen tools so we don't fail generating packages that the system cannot support -------------- - -# deb packages use underbars, and package manager(s) seem to flip the *_64 processor type -# to the old (non-standard) amd64 string, so we do it here for consistency. Set -DPRESERVE_PTYPE=1 -# to prevent the flip. RPM packages will always be given the system generated processor type string. -# -if( ${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64" ) - if( NOT PRESERVE_PTYPE ) - set( deb_sys_name "amd64" ) - else() - set( deb_sys_name ${CMAKE_SYSTEM_PROCESSOR} ) - endif() -else() - set( deb_sys_name ${CMAKE_SYSTEM_PROCESSOR} ) -endif() -unset( PRESERVE_PTYPE CACHE ) # we don't want this to persist - -set( rpm_sys_name ${CMAKE_SYSTEM_PROCESSOR} ) - -if( DEV_PKG ) - set( deb_pkg_name "ricxfcpp-dev" ) - set( rpm_pkg_name "ricxfcpp-devel" ) -else() - set( deb_pkg_name "ricxfcpp" ) - set( rpm_pkg_name "ricxfcpp" ) -endif() - -set( pkg_label "ricxfcpp${spoiled_str}-${major_version}.${minor_version}.${patch_level}-${sys_name}" ) -set( rpm_pkg_label "${rpm_pkg_name}${spoiled_str}-${major_version}.${minor_version}.${patch_level}-${rpm_sys_name}" ) -set( deb_pkg_label "${deb_pkg_name}${spoiled_str}_${major_version}.${minor_version}.${patch_level}_${deb_sys_name}" ) -message( "+++ pkg name: ${deb_pkg_label}.deb" ) - -set( gen_rpm 0 ) -find_program( rpm NAMES rpmbuild ) # rpm package gen requires this to be installed -if( "${rpm}" MATCHES "rpm-NOTFOUND" ) # cannot build rpm - set( pkg_list "DEB" ) - message( "### make package will generate only deb package; cannot find support to generate rpm packages" ) -else() - message( "+++ pkg name: ${rpm_pkg_label}.rpm" ) # debugging if we think we can gen rpm too - set( pkg_list "DEB;RPM" ) - set( gen_rpm 1 ) - message( "+++ make package will generate both deb and rpm packages" ) -endif() - - - -# this gets us round a chicken/egg problem. include files don't exist until make is run -# but Cmake insists on having these exist when we add them to include directories to -# enable code to find them after we build them. -# -include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/src/messaging" ) - - # Compiler flags # set( CMAKE_POSITION_INDEPENDENT_CODE ON ) -set( CMAKE_C_FLAGS "-g " ) -set( CMAKE_CPP_FLAGS "-g " ) if( GPROF ) # if set, we'll set profiling flag on compiles message( "+++ profiling is on" ) set( CMAKE_C_FLAGS "-pg " ) set( CMAKE_CPP_FLAGS "-pg " ) else() + set( CMAKE_C_FLAGS "-g " ) + set( CMAKE_CPP_FLAGS "-g " ) message( "+++ profiling is off" ) endif() -unset( GPROF CACHE ) # we don't want this to persist - -# Include modules -add_subdirectory( src/messaging ) -add_subdirectory( src/xapp ) -#add_subdirectory( doc ) # this will auto skip if {X}fm is not available - +unset( GPROF CACHE ) # ensure this does not persist -# shared and static libraries are built from the same object files. -# -add_library( ricxfcpp_shared SHARED "$;$" ) -set_target_properties( ricxfcpp_shared - PROPERTIES - OUTPUT_NAME "ricxfcpp" - SOVERSION ${major_version} - VERSION ${major_version}.${minor_version}.${patch_level} -) -target_include_directories( ricxfcpp_shared PUBLIC "src/messenger" "src/xapp" ) +# each binary is built from a subset +add_subdirectory( src/ts_xapp ) -# we only build/export the static archive (.a) if generating a dev package -if( DEV_PKG ) - add_library( ricxfcpp_static STATIC "$;$" ) - set_target_properties( ricxfcpp_static - PROPERTIES - OUTPUT_NAME "ricxfcpp" - SOVERSION ${major_version} - VERSION ${major_version}.${minor_version}.${patch_level} - ) - target_include_directories( ricxfcpp_static PUBLIC "src/messenger" "src/xapp" ) -endif() # -------- unit testing ------------------------------------------------------- enable_testing() @@ -206,60 +104,3 @@ add_test( COMMAND bash ../test/unit_test.sh -q WORKING_DIRECTORY ../test ) - - -# ------------- packaging ----------------------------------------------------- - -# Define what should be installed, and where they should go. For dev package we install -# only the RMr headers, man pages and archive (.a) files. The run-time package gets just -# the library (.so) files and nothing more. -# -if( DEV_PKG ) - set( target_list "ricxfcpp_static" ) -else() - set( target_list "ricxfcpp_shared" ) -endif() - -install( TARGETS ${target_list} EXPORT LibraryConfig - LIBRARY DESTINATION ${install_lib} - ARCHIVE DESTINATION ${install_lib} - PUBLIC_HEADER DESTINATION ${install_inc} -) - -unset( DEV_PKG CACHE ) # prevent from being a hidden setting if user redoes things - -IF( EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake" ) - include( InstallRequiredSystemLibraries ) - - set( CPACK_DEBIAN_PACKAGE_NAME ${deb_pkg_name} ) - set( CPACK_RPM_PACKAGE_NAME ${rpm_pkg_name} ) - - set( CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/local;/usr/local/bin;/usr/local/include;/usr/local/share;/usr/local/lib" ) - - set( CPACK_set_DESTDIR "on" ) - set( CPACK_PACKAGING_INSTALL_PREFIX "${install_root}" ) - set( CPACK_GENERATOR "${pkg_list}" ) - - set( CPACK_PACKAGE_DESCRIPTION "C++ framework for RIC xAPPs based on RMR." ) - set( CPACK_PACKAGE_DESCRIPTION_SUMMARY "RIC xAPP C++ framework library" ) - set( CPACK_PACKAGE_VENDOR "None" ) - set( CPACK_PACKAGE_CONTACT "None" ) - set( CPACK_PACKAGE_VERSION_MAJOR "${major_version}" ) - set( CPACK_PACKAGE_VERSION_MINOR "${minor_version}" ) - set( CPACK_PACKAGE_VERSION_PATCH "${patch_level}" ) - set( CPACK_PACKAGE "${pkg_label}" ) # generic name for old versions of cpack - set( CPACK_DEBIAN_FILE_NAME "${deb_pkg_label}.deb" ) - set( CPACK_RPM_FILE_NAME "${rpm_pkg_label}.rpm" ) - - # Future: define dependencies on RMR and other libs - - set( CPACK_DEBIAN_PACKAGE_PRIORITY "optional" ) - set( CPACK_DEBIAN_PACKAGE_SECTION "ric" ) - set( CPACK_DEBIAN_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR} ) - set( CPACK_RPM_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR} ) - - # this seems ingnored if included - #set( CPACK_COMPONENTS_ALL Libraries ApplicationData ) - - INCLUDE( CPack ) -ENDIF() diff --git a/Dockerfile b/Dockerfile index 1e29e25..1260ecd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,10 +29,9 @@ # Author: E. Scott Daniels # -------------------------------------------------------------------------------------- -# nexus seems to use ports rather than adding release, prod, staging to the url :( # the builder has: git, wget, cmake, gcc/g++, make, python2/3. v7 dropped nng support # -FROM nexus3.o-ran-sc.org:10004/bldr-ubuntu18-c-go:7-u18.04 as buildenv +FROM nexus3.o-ran-sc.org:10004/o-ran-sc/bldr-ubuntu18-c-go:8-u18.04 as buildenv # spaces to save things in the build image to copy to final image RUN mkdir -p /playpen/assets /playpen/src /playpen/bin @@ -68,11 +67,15 @@ RUN wget -nv --content-disposition ${PC_STG_URL}/sdl_${SDL_VER}-1_amd64.deb/down # -# build and install the application +# build and install the application(s) # -COPY examples/* /playpen/src/ -RUN cd /playpen/src && make && make install - +COPY . /playpen/src/ +RUN cd /playpen/src && \ + rm -fr .build &&\ + mkdir .build && \ + cd .build && \ + cmake .. && \ + make install # non-programme things that we need to push to final image # @@ -110,9 +113,9 @@ WORKDIR /data COPY --from=buildenv /playpen/assets/* /data # if needed, set RMR vars -#ENV RMR_RTG_SVC=rm-host:port -#ENV RMR_VCTL_FILE=/tmp/rmr.v ENV RMR_SEED_RT=/data/bootstrap.rt +#ENV RMR_RTG_SVC=rm-host:port +ENV RMR_VCTL_FILE=/tmp/rmr.v +RUN echo "2" >/tmp/rmr.v -#CMD [ "ts_xapp_start.sh" ] CMD [ "/usr/local/bin/ts_xapp" ] diff --git a/build_rmr.sh b/build_rmr.sh deleted file mode 100755 index 905a15d..0000000 --- a/build_rmr.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env ksh - -# Mnemonic: rmr_build.sh -# Abstract: This will pull RMR from the repo, build and install. This -# is en lieu of using wget to fetch the RMR package from some -# repo and installing it. The package method is preferred -# but if that breaks this can be used in place of it. - -rmr_ver=${1:-3.6.2} - -# assume that we're in the proper directory -set -e -git clone "https://gerrit.o-ran-sc.org/r/ric-plt/lib/rmr" - -cd rmr -git checkout $ver -mkdir .build -cd .build -cmake .. -DDEV_PKG=1 -DPACK_EXTERNALS=1 -make install -cmake .. -DDEV_PKG=0 -make install - diff --git a/container-tag.yaml b/container-tag.yaml new file mode 100644 index 0000000..f04677f --- /dev/null +++ b/container-tag.yaml @@ -0,0 +1,3 @@ +# this is used by CI jobs to apply a tag when it builds the image +--- +tag: '1.0.0' diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..89d0765 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +/_build +/out diff --git a/docs/_static/logo.png b/docs/_static/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c3b6ce56468d87a3d9463ee75297b3895fc9a414 GIT binary patch literal 43935 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

r@f1gRWk|A*%4`3la7*fhEBO++ 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 literal 0 HcmV?d00001 diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..922e22f --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,6 @@ +from docs_conf.conf import * +linkcheck_ignore = [ + 'http://localhost.*', + 'http://127.0.0.1.*', + 'https://gerrit.o-ran-sc.org.*' +] diff --git a/docs/conf.yaml b/docs/conf.yaml new file mode 100644 index 0000000..1fcb96e --- /dev/null +++ b/docs/conf.yaml @@ -0,0 +1,3 @@ +--- +project_cfg: oran +project: ric-app-ts diff --git a/docs/favicon.ico b/docs/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..00b0fd0ef0b4e78fbb8cdb413ce84561dfeb404f GIT binary patch literal 15086 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

4K$ruCE1 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 XY+}&}KC=mD;X?Iq*l*cA?B4$ePY*3q literal 0 HcmV?d00001 diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..b7d4ad6 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,20 @@ + +.. This work is licensed under a Creative Commons Attribution 4.0 International License. +.. SPDX-License-Identifier: CC-BY-4.0 + +Traffic Steering xAPP +===================== + +.. toctree:: + :maxdepth: 1 + :caption: Documents: + + user-guide.rst + +.. toctree:: + :maxdepth: 1 + :caption: Misc: + + rel-notes.rst + +* :ref:`search` diff --git a/docs/rel-notes.rst b/docs/rel-notes.rst new file mode 100644 index 0000000..2c0d29b --- /dev/null +++ b/docs/rel-notes.rst @@ -0,0 +1,16 @@ + +.. This work is licensed under a Creative Commons Attribution 4.0 International License. +.. SPDX-License-Identifier: CC-BY-4.0 + +.. CAUTION: this document is generated from source in doc/src/rtd. +.. To make changes edit the source and recompile the document. +.. Do NOT make changes directly to .rst or .md files. + +Traffic Steering xAPP +===================== + +2020 April 28 Version 1.0.0 +---------------------------- + + Initial release. + diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt new file mode 100644 index 0000000..09a0c1c --- /dev/null +++ b/docs/requirements-docs.txt @@ -0,0 +1,5 @@ +sphinx +sphinx-rtd-theme +sphinxcontrib-httpdomain +recommonmark +lfdocs-conf diff --git a/docs/user-guide.rst b/docs/user-guide.rst new file mode 100644 index 0000000..68ceddf --- /dev/null +++ b/docs/user-guide.rst @@ -0,0 +1,21 @@ + + +.. This work is licensed under a Creative Commons Attribution 4.0 International License. +.. SPDX-License-Identifier: CC-BY-4.0 +.. +.. CAUTION: this document is generated from source in doc/src/* +.. To make changes edit the source and recompile the document. +.. Do NOT make changes directly to .rst or .md files. + + +============ +User's Guide +============ +--------------------- +Traffic Steering xAPP +--------------------- + +Introduction +============ + +Some text about the traffic steering xAPP will eventually be added here. diff --git a/src/messaging/README b/src/messaging/README deleted file mode 100644 index 0683082..0000000 --- a/src/messaging/README +++ /dev/null @@ -1,47 +0,0 @@ - -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== - -This directory contains the source for the RMR messaging portion of the -framework. Specifially: - - message.* - provides a message class from which the user can extract/set information - (type, subscription ID, payload, etc.) and provides instance funcitons - for sending and replying to the message. User programmes will interact - directly with this. - - msg_component.* - This is a small type def that allows some of the getter functions in message - to return a smart pointer to memory which cannot directly be released (e.g - the payload). This allows the user programme to declare a variable of type - Msg_component (which is really a smart pointer with a custom deleter) rather - than having to understand the needed smart pointer construct for these things. - - messenger.* - This class provides the direct "wrapper" on top of RMR. It supports - high level operations such as Listen and callback management. - - callback.* - This provides the callback support to messenger (listen) functions. - - default_cb.* - This module contains any default callback functions which are provided - by the framework (e.g. health check processing). - - - diff --git a/src/messaging/callback.cpp b/src/messaging/callback.cpp deleted file mode 100644 index d4d697d..0000000 --- a/src/messaging/callback.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// vi: ts=4 sw=4 noet: -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - -/* - Mnemonic: callback.cpp - Abstract: Function defs for the callback managment object - Date: 9 March 2020 - Author: E. Scott Daniels -*/ - -#include - -#include - -#include "message.hpp" -//class Messenger; - - -/* - Builder. -*/ -Callback::Callback( user_callback ufun, void* data ) { // builder - user_fun = ufun; - udata = data; -} - -/* - there is nothing to be done from a destruction perspective, so no - destruction function needed at the moment. -*/ - -/* - Drive_cb will invoke the callback and pass along the stuff passed here. -*/ -void Callback::Drive_cb( Message& m ) { - if( user_fun != NULL ) { - user_fun( m, m.Get_mtype(), m.Get_subid(), m.Get_len(), m.Get_payload(), udata ); - } -} - - diff --git a/src/messaging/callback.hpp b/src/messaging/callback.hpp deleted file mode 100644 index b8e9dfa..0000000 --- a/src/messaging/callback.hpp +++ /dev/null @@ -1,52 +0,0 @@ -// vi: ts=4 sw=4 noet: -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - -/* - Mnemonic: callback.hpp - Abstract: class description for a callback managment object. - Date: 9 March 2020 - Author: E. Scott Daniels -*/ - - -#ifndef _CALLBACK_HPP -#define _CALLBACK_HPP - -#include - -class Messenger; -class Message; -#include "message.hpp" - -typedef void(*user_callback)( Message& m, int mtype, int subid, int payload_len, Msg_component payload, void* usr_data ); - -class Callback { - - private: - user_callback user_fun; - void* udata; // user data - - public: - Callback( user_callback, void* data ); // builder - void Drive_cb( Message& m ); // invoker -}; - - -#endif diff --git a/src/messaging/default_cb.cpp b/src/messaging/default_cb.cpp deleted file mode 100644 index 1083293..0000000 --- a/src/messaging/default_cb.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// vi: ts=4 sw=4 noet: -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - -/* - Mnemonic: default_cb.cpp - Abstract: This is a set of static functions that are used as - the default Messenger callbacks. - - Date: 11 Mar 2020 - Author: E. Scott Daniels -*/ - -#include -#include - -#include -#include - - -#include - -#include "messenger.hpp" - -/* - This is the default health check function that we provide (user - may override it). It will respond to health check messages by - sending an OK back to the source. - - The mr paramter is obviously ignored, but to add this as a callback - the function sig must match. -*/ -void Health_ck_cb( Message& mbuf, int mtype, int sid, int len, Msg_component payload, void* data ) { - unsigned char response[128]; - - snprintf( (char* ) response, sizeof( response ), "OK\n" ); - mbuf.Send_response( RIC_HEALTH_CHECK_RESP, sid, strlen( (char *) response )+1, response ); -} diff --git a/src/messaging/default_cb.hpp b/src/messaging/default_cb.hpp deleted file mode 100644 index 2e96003..0000000 --- a/src/messaging/default_cb.hpp +++ /dev/null @@ -1,39 +0,0 @@ -// vi: ts=4 sw=4 noet: -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - -/* - Mnemonic: default_cb.hpp - Abstract: Headers/prototypes for the default callbacks. The - default callbacks are those which we install when - the messenger is created and handles things that - the application might not want to (e.g. health check). - - Date: 11 March 2020 - Author: E. Scott Daniels -*/ - -#ifndef _DEF_CB_H -#define _DEF_CB_H - - -void Health_ck_cb( Message& mbuf, int mtype, int sid, int len, Msg_component payload, void* data ); - - -#endif diff --git a/src/messaging/message.cpp b/src/messaging/message.cpp deleted file mode 100644 index 30a0fbc..0000000 --- a/src/messaging/message.cpp +++ /dev/null @@ -1,419 +0,0 @@ -// vi: ts=4 sw=4 noet: -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - -/* - Mnemonic: message.cpp - Abstract: A message wrapper. This should completely hide the - underlying transport (RMR) message structure from - the user application. For the most part, the getters - are used by the framwork; it is unlikely that other - than adding/extracting the MEID, the user app will - be completely unaware of information that is not - presented in the callback parms. - - Date: 12 March 2020 - Author: E. Scott Daniels -*/ - -#include -#include - -#include - -#include - -#include "message.hpp" - -// --------------- private ------------------------------------------------ - -// --------------- builders/operators ------------------------------------- - -/* - Create a new message wrapper for an existing RMR msg buffer. -*/ -Message::Message( rmr_mbuf_t* mbuf, void* mrc ) { - this->mrc = mrc; // the message router context for sends - this->mbuf = mbuf; -} - -Message::Message( void* mrc, int payload_len ) { - this->mrc = mrc; - this->mbuf = rmr_alloc_msg( mrc, payload_len ); -} - -/* - Copy builder. Given a source object instance (soi), create a copy. - Creating a copy should be avoided as it can be SLOW! -*/ -Message::Message( const Message& soi ) { - int payload_size; - - mrc = soi.mrc; - payload_size = rmr_payload_size( soi.mbuf ); // rmr can handle a nil pointer - mbuf = rmr_realloc_payload( soi.mbuf, payload_size, RMR_COPY, RMR_CLONE ); -} - -/* - Assignment operator. Simiolar to the copycat, but "this" object exists and - may have data that needs to be released prior to making a copy of the soi. -*/ -Message& Message::operator=( const Message& soi ) { - int payload_size; - - if( this != &soi ) { // cannot do self assignment - if( mbuf != NULL ) { - rmr_free_msg( mbuf ); // release the old one so we don't leak - } - - payload_size = rmr_payload_size( soi.mbuf ); // rmr can handle a nil pointer - mrc = soi.mrc; - mbuf = rmr_realloc_payload( soi.mbuf, payload_size, RMR_COPY, RMR_CLONE ); - } - - return *this; -} - -/* - Move builder. Given a source object instance (soi), move the information from - the soi ensuring that the destriction of the soi doesn't trash things from - under us. -*/ -Message::Message( Message&& soi ) { - mrc = soi.mrc; - mbuf = soi.mbuf; - - soi.mrc = NULL; // prevent closing of RMR stuff on soi destroy - soi.mbuf = NULL; -} - -/* - Move Assignment operator. Move the message data to the existing object - ensure the object reference is cleaned up, and ensuring that the source - object references are removed. -*/ -Message& Message::operator=( Message&& soi ) { - if( this != &soi ) { // cannot do self assignment - if( mbuf != NULL ) { - rmr_free_msg( mbuf ); // release the old one so we don't leak - } - - mrc = soi.mrc; - mbuf = soi.mbuf; - - soi.mrc = NULL; - soi.mbuf = NULL; - } - - return *this; -} - - -/* - Destroyer. -*/ -Message::~Message() { - if( mbuf != NULL ) { - rmr_free_msg( mbuf ); - } - - mbuf = NULL; -} - - -// --- getters/setters ----------------------------------------------------- -/* - Copy the payload bytes, and return a smart pointer (unique) to it. - If the application needs to update the payload in place for a return - to sender call, or just to access the payload in a more efficent manner - (without the copy), the Get_payload() function should be considered. - - This function will return a NULL pointer if malloc fails. -*/ -//char* Message::Copy_payload( ){ -std::unique_ptr Message::Copy_payload( ){ - unsigned char* new_payload = NULL; - - if( mbuf != NULL ) { - new_payload = (unsigned char *) malloc( sizeof( unsigned char ) * mbuf->len ); - memcpy( new_payload, mbuf->payload, mbuf->len ); - } - - return std::unique_ptr( new_payload ); -} - -/* - Makes a copy of the MEID and returns a smart pointer to it. -*/ -std::unique_ptr Message::Get_meid(){ - unsigned char* m = NULL; - - m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_MEID ); - rmr_get_meid( mbuf, m ); - - return std::unique_ptr( m ); -} - -/* - Return the total size of the payload (the amount that can be written to - as opposed to the portion of the payload which is currently in use. - If mbuf isn't valid (nil, or message has a broken header) the return - will be -1. -*/ -int Message::Get_available_size(){ - return rmr_payload_size( mbuf ); // rmr can handle a nil pointer -} - -int Message::Get_mtype(){ - int rval = INVALID_MTYPE; - - if( mbuf != NULL ) { - rval = mbuf->mtype; - } - - return rval; -} - -/* - Makes a copy of the source field and returns a smart pointer to it. -*/ -std::unique_ptr Message::Get_src(){ - unsigned char* m = NULL; - - m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_SRC ); - memset( m, 0, sizeof( unsigned char ) * RMR_MAX_SRC ); - - if( m != NULL ) { - rmr_get_src( mbuf, m ); - } - - return std::unique_ptr( m ); -} - -int Message::Get_state( ){ - int state = INVALID_STATUS; - - if( mbuf != NULL ) { - state = mbuf->state; - } - - return state; -} - -int Message::Get_subid(){ - int rval = INVALID_SUBID; - - if( mbuf != NULL ) { - rval =mbuf->sub_id; - } - - return rval; -} - -/* - Return the amount of the payload (bytes) which is used. See - Get_available_size() to get the total usable space in the payload. -*/ -int Message::Get_len(){ - int rval = 0; - - if( mbuf != NULL ) { - rval = mbuf->len; - } - - return rval; -} - -/* - This returns a smart (unique) pointer to the payload portion of the - message. This provides the user application with the means to - update the payload in place to avoid multiple copies. The - user programme is responsible to determing the usable payload - length by calling Message:Get_available_size(), and ensuring that - writing beyond the indicated size does not happen. -*/ -Msg_component Message::Get_payload(){ - if( mbuf != NULL ) { - return std::unique_ptr( mbuf->payload ); - } - - return NULL; -} - -void Message::Set_meid( std::shared_ptr new_meid ) { - if( mbuf != NULL ) { - rmr_str2meid( mbuf, (unsigned char *) new_meid.get() ); - } -} - -void Message::Set_mtype( int new_type ){ - if( mbuf != NULL ) { - mbuf->mtype = new_type; - } -} - -void Message::Set_len( int new_len ){ - if( mbuf != NULL && new_len >= 0 ) { - mbuf->len = new_len; - } -} - -void Message::Set_subid( int new_subid ){ - if( mbuf != NULL ) { - mbuf->sub_id = new_subid; - } -} - - -// -------------- send functions --------------------------------- - -/* - This assumes that the contents of the mbuf were set by either a send attempt that - failed with a retry and thus is ready to be processed by RMR. - Exposed to the user, but not expected to be frequently used. -*/ -bool Message::Send( ) { - bool state = false; - - if( mbuf != NULL ) { - mbuf = rmr_send_msg( mrc, mbuf ); // send and pick up new mbuf - state = mbuf->state == RMR_OK; // overall state for caller - } - - return state; -} - -/* - Similar to Send(), this assumes that the message is already set up and this is a retry. - Exposed to the user, but not expected to be frequently used. -*/ -bool Message::Reply( ) { - bool state = false; - - if( mbuf != NULL ) { - mbuf = rmr_rts_msg( mrc, mbuf ); // send and pick up new mbuf - state = mbuf->state == RMR_OK; // state for caller based on send - } - - return state; -} - -/* - Send workhorse. - This will setup the message (type etc.) ensure the message payload space is - large enough and copy in the payload (if a new payload is given), then will - either send or rts the message based on the stype parm. - - If payload is nil, then we assume the user updated the payload in place and - no copy is needed. - - This is public, but most users should use Send_msg or Send_response functions. -*/ -bool Message::Send( int mtype, int subid, int payload_len, unsigned char* payload, int stype ) { - bool state = false; - - if( mbuf != NULL ) { - if( mtype != NO_CHANGE ) { - mbuf->mtype = mtype; - } - if( subid != NO_CHANGE ) { - mbuf->sub_id = subid; - } - - if( payload_len != NO_CHANGE ) { - mbuf->len = payload_len; - } - - if( payload != NULL ) { // if we have a payload, ensure msg has room, realloc if needed, then copy - mbuf = rmr_realloc_payload( mbuf, payload_len, RMR_NO_COPY, RMR_NO_CLONE ); // ensure message is large enough - if( mbuf == NULL ) { - return false; - } - - memcpy( mbuf->payload, payload, mbuf->len ); - } - - if( stype == RESPONSE ) { - mbuf = rmr_rts_msg( mrc, mbuf ); - } else { - mbuf = rmr_send_msg( mrc, mbuf ); - } - - state = mbuf->state == RMR_OK; - } - - return state; -} - -/* - Send a response to the endpoint that sent the original message. - - Response can be null and the assumption will be that the message payload - was updated in place and no additional copy is needed before sending the message. - - The second form of the call allows for a stack allocated buffer (e.g. char foo[120]) to - be passed as the payload. -*/ -bool Message::Send_response( int mtype, int subid, int response_len, std::shared_ptr response ) { - return Send( mtype, subid, response_len, response.get(), RESPONSE ); -} - -bool Message::Send_response( int mtype, int subid, int response_len, unsigned char* response ) { - return Send( mtype, subid, response_len, response, RESPONSE ); -} - -/* - These allow a response message to be sent without changing the mtype/subid. -*/ -bool Message::Send_response( int response_len, std::shared_ptr response ) { - return Send( NO_CHANGE, NO_CHANGE, response_len, response.get(), RESPONSE ); -} - -bool Message::Send_response( int response_len, unsigned char* response ) { - return Send( NO_CHANGE, NO_CHANGE, response_len, response, RESPONSE ); -} - - -/* - Send a message based on message type routing. - - Payload can be null and the assumption will be that the message payload - was updated in place and no additional copy is needed before sending the message. - - Return is a new mbuf suitable for sending another message, or the original buffer with - a bad state sent if there was a failure. -*/ -bool Message::Send_msg( int mtype, int subid, int payload_len, std::shared_ptr payload ) { - return Send( mtype, subid, payload_len, payload.get(), MESSAGE ); -} - -bool Message::Send_msg( int mtype, int subid, int payload_len, unsigned char* payload ) { - return Send( mtype, subid, payload_len, payload, MESSAGE ); -} - -/* - Similar send functions that allow the message type/subid to remain unchanged -*/ -bool Message::Send_msg( int payload_len, std::shared_ptr payload ) { - return Send( NO_CHANGE, NO_CHANGE, payload_len, payload.get(), MESSAGE ); -} - -bool Message::Send_msg( int payload_len, unsigned char* payload ) { - return Send( NO_CHANGE, NO_CHANGE, payload_len, payload, MESSAGE ); -} diff --git a/src/messaging/message.hpp b/src/messaging/message.hpp deleted file mode 100644 index 0db0927..0000000 --- a/src/messaging/message.hpp +++ /dev/null @@ -1,110 +0,0 @@ -// vi: ts=4 sw=4 noet: -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - -/* - Mnemonic: message.hpp - Abstract: Headers for the message class. - This class provides an interface to the user application - when information from the message is needed. - - Date: 10 March 2020 - Author: E. Scott Daniels -*/ - -#ifndef _MESSAGE_HPP -#define _MESSAGE_HPP - - -#include -#include - -#include - -#include "msg_component.hpp" -#include "callback.hpp" -#include "default_cb.hpp" - -#ifndef RMR_NO_CLONE - #define RMR_NO_CLONE 0 - #define RMR_NO_COPY 0 - #define RMR_CLONE 1 - #define RMR_COPY 1 -#endif - - -// ------------------------------------------------------------------------ - -class Message { - private: - rmr_mbuf_t* mbuf; // the underlying RMR message buffer - void* mrc; // message router context - std::shared_ptr psp; // shared pointer to the payload to give out - - public: - static const int NO_CHANGE = -99; // indicates no change to a send/reply parameter - static const int INVALID_MTYPE = -1; - static const int INVALID_STATUS = -1; - static const int INVALID_SUBID = -2; - static const int NO_SUBID = -1; // not all messages have a subid - - static const int RESPONSE = 0; // send types - static const int MESSAGE = 1; - - Message( rmr_mbuf_t* mbuf, void* mrc ); // builders - Message( void* mrc, int payload_len ); - Message( const Message& soi ); // copy cat - Message& operator=( const Message& soi ); // copy operator - Message( Message&& soi ); // mover - Message& operator=( Message&& soi ); // move operator - ~Message(); // destroyer - - std::unique_ptr Copy_payload( ); // copy the payload; deletable smart pointer - - std::unique_ptr Get_meid(); // returns a copy of the meid bytes - int Get_available_size(); - int Get_len(); - int Get_mtype(); - Msg_component Get_payload(); - std::unique_ptr Get_src(); - int Get_state( ); - int Get_subid(); - - void Set_meid( std::shared_ptr new_meid ); - void Set_mtype( int new_type ); - void Set_subid( int new_subid ); - void Set_len( int new_len ); - - bool Reply( ); - bool Send( ); - bool Send( int mtype, int subid, int payload_len, unsigned char* payload, int stype ); - - bool Send_msg( int mtype, int subid, int payload_len, std::shared_ptr payload ); - bool Send_msg( int mtype, int subid, int payload_len, unsigned char* payload ); - bool Send_msg( int payload_len, std::shared_ptr payload ); - bool Send_msg( int payload_len, unsigned char* payload ); - - bool Send_response( int mtype, int subid, int payload_len, std::shared_ptr response ); - bool Send_response( int mtype, int subid, int payload_len, unsigned char* response ); - bool Send_response( int payload_len, std::shared_ptr response ); - bool Send_response( int payload_len, unsigned char* response ); -}; - - -#endif diff --git a/src/messaging/messenger.cpp b/src/messaging/messenger.cpp deleted file mode 100644 index 24fe164..0000000 --- a/src/messaging/messenger.cpp +++ /dev/null @@ -1,279 +0,0 @@ -// vi: ts=4 sw=4 noet: -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - -/* - Mnemonic: messenger.cpp - Abstract: Message Router Messenger. - - Date: 10 March 2020 - Author: E. Scott Daniels -*/ - -#include -#include - -#include -#include - - -#include -#include -#include -#include -#include - -#include "callback.hpp" -#include "default_cb.hpp" // default callback prototypes -#include "message.hpp" -#include "messenger.hpp" - - -// --------------- private ----------------------------------------------------- - - -// ---------------- C++ buggerd up way of maintining class constants ---------- -const int Messenger::MAX_PAYLOAD = (1024*64); -const int Messenger::DEFAULT_CALLBACK = -1; - -// --------------- builders ----------------------------------------------- -/* - If wait4table is true, then the construction of the object does not - complete until the underlying transport has a new copy of the route - table. - - If port is nil, then the default port is used (4560). -*/ -Messenger::Messenger( char* port, bool wait4table ) { - if( port == NULL ) { - port = (char *) "4560"; - } - - gate = new std::mutex(); - listen_port = strdup( port ); - mrc = rmr_init( listen_port, Messenger::MAX_PAYLOAD, 0 ); - - if( wait4table ) { - this->Wait_for_cts( 0 ); - } - - Add_msg_cb( RIC_HEALTH_CHECK_REQ, Health_ck_cb, NULL ); // add our default call backs - - ok_2_run = true; -} - -/* - Move support. We DO allow the instance to be moved as only one copy - remains following the move. - Given a source object instance (soi) we move the information to - the new object, and then DELETE what was moved so that when the - user frees the soi, it doesn't destroy what we snarfed. -*/ -Messenger::Messenger( Messenger&& soi ) { - mrc = soi.mrc; - listen_port = soi.listen_port; - ok_2_run = soi.ok_2_run; - gate = soi.gate; - cb_hash = soi.cb_hash; // this seems dodgy - - soi.gate = NULL; - soi.listen_port = NULL; - soi.mrc = NULL; -} - -/* - Move operator. Given a source object instance, movee it's contents - to this insance. We must first clean up this instance. -*/ -Messenger& Messenger::operator=( Messenger&& soi ) { - if( this != &soi ) { // cannot move onto ourself - if( mrc != NULL ) { - rmr_close( mrc ); - } - if( listen_port != NULL ) { - free( listen_port ); - } - - mrc = soi.mrc; - listen_port = soi.listen_port; - ok_2_run = soi.ok_2_run; - gate = soi.gate; - cb_hash = soi.cb_hash; // this seems dodgy - - soi.gate = NULL; - soi.listen_port = NULL; - soi.mrc = NULL; - } - - return *this; -} - -/* - Destroyer. -*/ -Messenger::~Messenger() { - if( mrc != NULL ) { - rmr_close( mrc ); - } - - if( listen_port != NULL ) { - free( listen_port ); - } -} - -/* - Allow user to register a callback function invoked when a specific type of - message is received. The user may pass an optional data pointer which - will be passed to the function when it is called. The function signature - must be: - void fun( Messenger* mr, rmr_mbuf_t* mbuf, void* data ); - - The user can also invoke this function to set the "default" callback by - passing Messenger::DEFAULT_CALLBACK as the mtype. If no other callback - is defined for a message type, the default callback function is invoked. - If a default is not provided, a non-matching message is silently dropped. -*/ -void Messenger::Add_msg_cb( int mtype, user_callback fun_name, void* data ) { - Callback* cb; - - cb = new Callback( fun_name, data ); - cb_hash[mtype] = cb; - - callbacks = true; -} - -/* - Message allocation for user to send. User must destroy the message when - finished, but may keep the message for as long as is necessary - and reuse it over and over. -*/ -//Message* Messenger::Alloc_msg( int payload_size ) { -std::unique_ptr Messenger::Alloc_msg( int payload_size ) { - return std::unique_ptr( new Message( mrc, payload_size ) ); -} - -void Messenger::Listen( ) { - int count = 0; - rmr_mbuf_t* mbuf = NULL; - std::map::iterator mi; // map iterator; silly indirect way to point at the value - Callback* dcb = NULL; // default callback so we don't search - Callback* sel_cb; // callback selected to invoke - std::unique_ptrm; - - if( mrc == NULL ) { - return; - } - - mi = cb_hash.find( DEFAULT_CALLBACK ); - if( mi != cb_hash.end() ) { - dcb = mi->second; // oddly named second field is the address of the callback block - } - - while( ok_2_run ) { - mbuf = rmr_torcv_msg( mrc, mbuf, 2000 ); // come up for air every 2 sec to check ok2run - if( mbuf != NULL ) { - if( mbuf->state == RMR_OK ) { - m = std::unique_ptr( new Message( mbuf, mrc ) ); // auto delteted when scope terminates - - sel_cb = dcb; // start with default - if( callbacks && ((mi = cb_hash.find( mbuf->mtype )) != cb_hash.end()) ) { - sel_cb = mi->second; // override with user callback - } - if( sel_cb != NULL ) { - sel_cb->Drive_cb( *m ); // drive the selected one - mbuf = NULL; // not safe to use after given to cb - } - } else { - if( mbuf->state != RMR_ERR_TIMEOUT ) { - fprintf( stderr, " got bad status: %d\n", mbuf->state ); - } - } - } - } -} - -/* - Wait for the next message, up to a max timout, and return the message received. -*/ -std::unique_ptr Messenger::Receive( int timeout ) { - rmr_mbuf_t* mbuf = NULL; - std::unique_ptr m = NULL; - - if( mrc != NULL ) { - mbuf = rmr_torcv_msg( mrc, mbuf, timeout ); // future: do we want to reuse the mbuf here? - if( mbuf != NULL ) { - m = std::unique_ptr( new Message( mbuf, mrc ) ); - } - } - - return m; -} - -/* - Called to gracefully stop all listeners. -*/ -void Messenger::Stop( ) { - ok_2_run = false; -} - -/* - RMR messages must be released by RMR as there might be transport - buffers that have to be dealt with. Every callback is expected to - call this function when finished with the message. -void Messenger::Release_mbuf( void* vmbuf ) { - rmr_free_msg( (rmr_mbuf_t *) vmbuf ); -} -*/ - -/* - Wait for clear to send. - Until RMR loads a route table, all sends will fail with a - "no endpoint" state. This function allows the user application - to block until RMR has a viable route table. It does not guarentee - that every message that the user app will try to send has an entry. - - The use of this function by the user application allows for the - parallel initialisation of the application while waiting for the - route table service to generate a table for the application. The - initialisation function may be callsed with "no wait" and this - function invoked when the application has completed initialisation - and is ready to start sending messages. - - The max wait parameter is the maximum number of seconds to block. - If RMR never reports ready false is returned. A true return - incidcates all is ready. If max_wait is 0, then this will only - return when RMR is ready to send. -*/ -bool Messenger::Wait_for_cts( int max_wait ) { - bool block_4ever; - bool state = false; - - block_4ever = max_wait == 0; - while( block_4ever || max_wait > 0 ) { - if( rmr_ready( mrc ) ) { - state = true; - break; - } - - sleep( 1 ); - max_wait--; - } - - return state; -} diff --git a/src/messaging/messenger.hpp b/src/messaging/messenger.hpp deleted file mode 100644 index 0810aeb..0000000 --- a/src/messaging/messenger.hpp +++ /dev/null @@ -1,82 +0,0 @@ -// vi: ts=4 sw=4 noet: -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - - -/* - Mnemonic: messenger.hpp - Abstract: Headers for the messenger class - - Date: 10 March 2020 - Author: E. Scott Daniels -*/ - -#ifndef _messenger_hpp -#define _messenger_hpp - - -#include -#include -#include -#include -#include - -#include - -#include "message.hpp" - -#ifndef RMR_FALSE - #define RMR_FALSE 0 - #define RMR_TRUE 1 -#endif - -class Messenger { - - private: - std::map cb_hash; // callback functions associated with message types - std::mutex* gate; // overall mutex should we need searialisation - bool ok_2_run; - bool callbacks = false; // true if callbacks are defined - void* mrc; // message router context - char* listen_port; // port we ask msg router to listen on - - // copy and assignment are PRIVATE so that they fail if xapp tries; messenger cannot be copied! - Messenger( const Messenger& soi ); - Messenger& operator=( const Messenger& soi ); - - public: - // -- constants which need an instance; that happens as a global in the .cpp file (wtf C++) - static const int MAX_PAYLOAD; // max message size we'll handle - static const int DEFAULT_CALLBACK; // parm for add callback to set default - - Messenger( char* port, bool wait4table ); // builder - Messenger( Messenger&& soi ); // move construction - Messenger& operator=( Messenger&& soi ); // move operator - ~Messenger(); // destroyer - - void Add_msg_cb( int mtype, user_callback fun_name, void* data ); - std::unique_ptr Alloc_msg( int payload_size ); // message allocation - void Listen( ); // lisen driver - std::unique_ptr Receive( int timeout ); // receive 1 message - void Stop( ); // force to stop - //void Release_mbuf( void* vmbuf ); - bool Wait_for_cts( int max_wait ); -}; - -#endif diff --git a/src/messaging/msg_component.hpp b/src/messaging/msg_component.hpp deleted file mode 100644 index d707257..0000000 --- a/src/messaging/msg_component.hpp +++ /dev/null @@ -1,57 +0,0 @@ -// vi: ts=4 sw=4 noet: -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - -/* - Mnemonic: msg_component.hpp - Abstract: Defines a message component type which is needed in order - to use smart pointers (unique) to point at bytes in the - RMR message (which are not directly allocated and cannot - be freed/deleted outside of RMR (require a special destruction - call in the smart pointer). - - Date: 17 March 2020 - Author: E. Scott Daniels -*/ - -#ifndef _MSG_COMPONENT_HPP -#define _MSG_COMPONENT_HPP - -#include - -// -------------- smart pointer support -------------------------------- -/* - Pointers to a lot of things in the RMR message aren't directly - allocated and thus cannot be directly freed. To return a smart - pointer to these we have to ensure that no attempt to free/delete - the reference is made. This struct defines a type with a function - pointer (operator) that is 'registered' as the delete function for - such a smart pointer, and does _nothing_ when called. -*/ -typedef struct { - void operator()( unsigned char * p ){} -} unfreeable; - -/* - A 'generic' smart pointer to a component in the message which cannot - be directly freed (e.g. the payload, meid, etc). -*/ -using Msg_component = std::unique_ptr; - -#endif diff --git a/src/messaging/CMakeLists.txt b/src/ts_xapp/CMakeLists.txt similarity index 53% rename from src/messaging/CMakeLists.txt rename to src/ts_xapp/CMakeLists.txt index 507da84..06ea5f2 100644 --- a/src/messaging/CMakeLists.txt +++ b/src/ts_xapp/CMakeLists.txt @@ -1,10 +1,7 @@ -# vim: sw=4 ts=4 noet: -# #================================================================================== -# Copyright (c) 2020 Nokia -# Copyright (c) 2020 AT&T Intellectual Property. +# Copyright (c) 2020 AT&T Intellectual Property. # -# Licensed under the Apache License, Version 2.0 (the "License"); +# 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 # @@ -18,30 +15,11 @@ #================================================================================== # +add_executable( ts_xapp ts_xapp.cpp ) +target_link_libraries( ts_xapp ricxfcpp;rmr_si;sdl;pthread ) -# For clarity: this generates object, not a lib as the CM command implies. -# -add_library( message_objects OBJECT - callback.cpp - default_cb.cpp - message.cpp - messenger.cpp +install( + TARGETS ts_xapp + DESTINATION ${install_bin} ) -target_include_directories (message_objects PUBLIC - $ - $ - PRIVATE src) - -# header files should go into .../include/xfcpp/ -if( DEV_PKG ) - install( FILES - callback.hpp - default_cb.hpp - message.hpp - messenger.hpp - msg_component.hpp - DESTINATION ${install_inc} - ) -endif() - diff --git a/src/xapp/CMakeLists.txt b/src/ts_xapp/Makefile similarity index 58% rename from src/xapp/CMakeLists.txt rename to src/ts_xapp/Makefile index 093ef6f..08a350b 100644 --- a/src/xapp/CMakeLists.txt +++ b/src/ts_xapp/Makefile @@ -1,8 +1,8 @@ -# vim: sw=4 ts=4 noet: -# +# vim: ts=4 sw=4 noet: + #================================================================================== -# Copyright (c) 2020 Nokia -# Copyright (c) 2020 AT&T Intellectual Property. +# Copyright (c) 2020 Nokia +# Copyright (c) 2020 AT&T Intellectual Property. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,25 +16,18 @@ # See the License for the specific language governing permissions and # limitations under the License. #================================================================================== -# +# simple makefile to build the examples. This assumes that the xapp framework +# library has been installed or the LD_LIBRARY_PATH and C_INCLUDE_PATH environent +# variables are set to reference the needed files. -# For clarity: this generates object, not a lib as the CM command implies. -# -add_library( xapp_objects OBJECT - xapp.cpp -) +%.o:: %.cpp %.hpp + g++ -g ${prereq%% *} -c -target_include_directories (xapp_objects PUBLIC - $ - $ - PRIVATE src) +% :: %.cpp + g++ $< -g -o $@ -lricxfcpp -lrmr_si -lpthread -lm -lsdl -# header files should go into .../include/xfcpp/ -if( DEV_PKG ) - install( FILES - xapp.hpp - DESTINATION ${install_inc} - ) -endif() +all:: ts_xapp +install:: + cp ts_xapp /usr/local/bin/ diff --git a/examples/ts_xapp.cpp~ b/src/ts_xapp/ts_xapp.cpp similarity index 98% rename from examples/ts_xapp.cpp~ rename to src/ts_xapp/ts_xapp.cpp index 9ccd4b5..f6e2c37 100644 --- a/examples/ts_xapp.cpp~ +++ b/src/ts_xapp/ts_xapp.cpp @@ -98,13 +98,13 @@ void policy_callback( Message& mbuf, int mtype, int subid, int len, Msg_componen fprintf(stderr, "cb 2"); send_payload = msg->Get_payload(); // direct access to payload - snprintf( (char *) send_payload.get(), 2048, "{\"UEPredictionSet\" : [\"222\", \"333\", \"444\"]}", i ); + snprintf( (char *) send_payload.get(), 2048, "{\"UEPredictionSet\" : [\"222\", \"333\", \"444\"]}" ); fprintf(stderr, "cb 3"); // payload updated in place, nothing to copy from, so payload parm is nil if ( ! msg->Send_msg( mtype, Message::NO_SUBID, strlen( (char *) send_payload.get() )+1, NULL )) { - fprintf( stderr, " send failed: %d\n", i ); + fprintf( stderr, " send failed: %d\n", msg->Get_state() ); } fprintf(stderr, "cb 4"); @@ -163,7 +163,7 @@ extern int main( int argc, char** argv ) { int delay = 1000000; // mu-sec delay; default 1s - char* port = (char *) "4555"; + char* port = (char *) "4560"; int ai; diff --git a/src/xapp/README b/src/xapp/README deleted file mode 100644 index 39391b2..0000000 --- a/src/xapp/README +++ /dev/null @@ -1,27 +0,0 @@ - -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== - -This directory contains the source for the overall Xapp class. -Specifially: - - xapp.* - Is the class that the user creates in their application. It provides, by - extension, the RMR messaging functions. - - - diff --git a/src/xapp/xapp.cpp b/src/xapp/xapp.cpp deleted file mode 100644 index 8feb52e..0000000 --- a/src/xapp/xapp.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// vi: ts=4 sw=4 noet: -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - -/* - Mnemonic: xapp.cpp - Abstract: The main xapp class. - This class actually extends the messenger class as most of what - would be done here is just passing through to the messenger. - - Date: 13 March 2020 - Author: E. Scott Daniels -*/ - -#include -#include - -#include -#include - - -#include -#include - -#include -#include "xapp.hpp" - -// --------------- private ----------------------------------------------------- - - - -// --------------- builders ----------------------------------------------- - -/* - If wait4table is true, then the construction of the object does not - complete until the underlying transport has a new copy of the route - table. - - If port is nil, then the default port is used (4560). -*/ -Xapp::Xapp( char* port, bool wait4table ) : Messenger( port, wait4table ) { - // nothing to do; all handled in Messenger constructor -} - -/* - Destroyer. -*/ -Xapp::~Xapp() { - // nothing to destroy; superclass destruction is magically invoked. -} - -/* - Start n threads, each running a listener which will drive callbacks. - - The final listener is started in the main thread; in otherwords this - function won't return unless that listener crashes. -*/ -void Xapp::Run( int nthreads ) { - int i; - std::thread** tinfo; // each thread we'll start - - tinfo = new std::thread* [nthreads-1]; - - for( i = 0; i < nthreads - 1; i++ ) { // thread for each n-1; last runs here - tinfo[i] = new std::thread( &Xapp::Listen, this ); - } - - this->Listen(); // will return only when halted - - for( i = 0; i < nthreads - 1; i++ ) { // wait for others to stop - tinfo[i]->join(); - } - - delete tinfo; -} - -/* - Halt the xapp. This will drive the messenger's stop function to prevent any - active listeners from running, and will shut things down. -*/ -void Xapp::Halt() { - this->Stop(); // messenger shut off -} - diff --git a/src/xapp/xapp.hpp b/src/xapp/xapp.hpp deleted file mode 100644 index 83540ec..0000000 --- a/src/xapp/xapp.hpp +++ /dev/null @@ -1,63 +0,0 @@ -// vi: ts=4 sw=4 noet: -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - -/* - Mnemonic: xapp.hpp - Abstract: Headers for the xapp class. This class extends the messenger class - as most of the function of this class would be just passing through - calls to the messenger object. - - Date: 13 March 2020 - Author: E. Scott Daniels -*/ - -#ifndef _xapp_hpp -#define _xapp_hpp - - -#include -#include -#include -#include - -#include - -#include "callback.hpp" -#include "messenger.hpp" - -class Xapp : public Messenger { - - private: - std::string name; - - // copy and assignment are PRIVATE because we cant "clone" the listen environment - Xapp( const Xapp& soi ); - Xapp& operator=( const Xapp& soi ); - - public: - Xapp( char* listen_port, bool wait4rt ); // builder - Xapp( ); - ~Xapp(); // destroyer - - void Run( int nthreads ); // message listen driver - void Halt( ); // force to stop -}; - -#endif diff --git a/test/rmr_em.c b/test/rmr_em.c deleted file mode 100644 index c9f85cf..0000000 --- a/test/rmr_em.c +++ /dev/null @@ -1,255 +0,0 @@ -// vim: ts=4 sw=4 noet : -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - -/* - Mnemonic: rmr_em.c - Abstract: RMR emulation for testing - - Date: 20 March - Author: E. Scott Daniels -*/ - -#include -#include -#include - - -/* - CAUTION: this is a copy of what is in RMR and it is needed as some of the framework - functions access the 'public' fields like state and mtype. -*/ -typedef struct { - int state; // state of processing - int mtype; // message type - int len; // length of data in the payload (send or received) - unsigned char* payload; // transported data - unsigned char* xaction; // pointer to fixed length transaction id bytes - int sub_id; // subscription id - int tp_state; // transport state (errno) valid only if state != RMR_OK, and even then may not be valid - - // these things are off limits to the user application - void* tp_buf; // underlying transport allocated pointer (e.g. nng message) - void* header; // internal message header (whole buffer: header+payload) - unsigned char* id; // if we need an ID in the message separate from the xaction id - int flags; // various MFL_ (private) flags as needed - int alloc_len; // the length of the allocated space (hdr+payload) - - void* ring; // ring this buffer should be queued back to - int rts_fd; // SI fd for return to sender - - int cookie; // cookie to detect user misuse of free'd msg -} rmr_mbuf_t; - -typedef struct { - char meid[32]; - char src[32]; -} header_t; - - -void* rmr_init( char* port, int flags ) { - return malloc( sizeof( char ) * 100 ); -} - -rmr_mbuf_t* rmr_alloc_msg( void* mrc, int payload_len ) { - rmr_mbuf_t* mbuf; - char* p; // the tp buffer; also the payload - header_t* h; - int len; - - len = (sizeof( char ) * payload_len) + sizeof( header_t ); - p = (char *) malloc( len ); - if( p == NULL ) { - return NULL; - } - h = (header_t *) p; - memset( p, 0, len ); - - mbuf = (rmr_mbuf_t *) malloc( sizeof( rmr_mbuf_t ) ); - if( mbuf == NULL ) { - free( p ); - return NULL; - } - memset( mbuf, 0, sizeof( rmr_mbuf_t ) ); - - mbuf->tp_buf = p; - mbuf->payload = (char *)p + sizeof( header_t ); - - - mbuf->len = 0; - mbuf->alloc_len = payload_len; - mbuf->payload = (void *) p; - strncpy( h->src, "host:ip", 8 ); - strncpy( h->meid, "EniMeini", 9 ); - - return mbuf; -} - -void rmr_free_msg( rmr_mbuf_t* mbuf ) { - if( mbuf ) { - if( mbuf->tp_buf ) { - free( mbuf->tp_buf ); - } - free( mbuf ); - } -} - -char* rmr_get_meid( rmr_mbuf_t* mbuf, char* m ) { - header_t* h; - - if( mbuf != NULL ) { - if( m == NULL ) { - m = (char *) malloc( sizeof( char ) * 32 ); - } - h = (header_t *) mbuf->tp_buf; - memcpy( m, h->meid, 32 ); - } - - return m; -} - -int rmr_payload_size( rmr_mbuf_t* mbuf ) { - - if( mbuf != NULL ) { - return mbuf->alloc_len; - } - - return 0; -} - -char *rmr_get_src( rmr_mbuf_t* mbuf, char *m ) { - header_t* h; - - if( mbuf != NULL ) { - if( m == NULL ) { - m = (char *) malloc( sizeof( char ) * 32 ); - } - h = (header_t *) mbuf->tp_buf; - memcpy( m, h->src, 32 ); - } - - return m; -} - -int rmr_str2meid( rmr_mbuf_t* mbuf, unsigned char* s ) { - header_t* h; - - if( mbuf != NULL ) { - if( s == NULL ) { - return 1; - } - - if( strlen( s ) > 31 ) { - return 1; - } - - h = (header_t *) mbuf->tp_buf; - strncpy( h->meid, s, 32 ); - return 0; - } - - return 1; -} - -rmr_mbuf_t* rmr_send_msg( void* mrc, rmr_mbuf_t* mbuf ) { - - if( mbuf != NULL ) { - mbuf->state = 0; - } - - return mbuf; -} - -rmr_mbuf_t* rmr_rts_msg( void* mrc, rmr_mbuf_t* mbuf ) { - - if( mbuf != NULL ) { - mbuf->state = 0; - } - - return mbuf; -} - -rmr_mbuf_t* rmr_realloc_payload( rmr_mbuf_t* mbuf, int payload_len, int copy, int clone ) { // ensure message is large enough - rmr_mbuf_t* nmb; - unsigned char* payload; - - if( mbuf == NULL ) { - return NULL; - } - - nmb = rmr_alloc_msg( NULL, payload_len ); - if( copy ) { - memcpy( nmb->payload, mbuf->payload, mbuf->len ); - nmb->len = mbuf->len; - } else { - nmb->len = 0; - } - nmb->state = mbuf->state; - - if( ! clone ) { - free( mbuf ); - } - return nmb; -} - -void rmr_close( void* mrc ) { - return; -} - -rmr_mbuf_t* rmr_torcv_msg( void* mrc, rmr_mbuf_t* mbuf, int timeout ) { - static int max2receive = 500; - static int mtype = 0; - - if( mbuf == NULL ) { - mbuf = rmr_alloc_msg( NULL, 2048 ); - } - - if( max2receive <= 0 ) { - mbuf->state = 12; - mbuf->len = 0; - mbuf->mtype = -1; - mbuf->sub_id = -1; - } - - max2receive--; - - mbuf->state = 0; - mbuf->len = 80; - mbuf->mtype = mtype; - mbuf->sub_id = -1; - - mtype++; - if( mtype > 100 ) { - mtype = 0; - } - - return mbuf; -} - -int rmr_ready( void* mrc ) { - static int state = 0; - - if( ! state ) { - state = 1; - return 0; - } - - return 1; -} - diff --git a/test/unit_test.cpp b/test/unit_test.cpp deleted file mode 100644 index b0612d8..0000000 --- a/test/unit_test.cpp +++ /dev/null @@ -1,302 +0,0 @@ -// vim: ts=4 sw=4 noet : -/* -================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. - - 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. -================================================================================== -*/ - -/* - Mnemonic: Unit_test.cpp - Abstract: This is the unit test driver for the C++ xAPP framework. It - operates by including all of the modules directly (in order - to build them with the necessary coverage flags), then - drives all that it can. The RMR emulation module provides - emulated RMR functions which simulate the creation, sending - and receiving of messages etc. - - Date: 20 March 2020 - Author: E. Scott Daniels -*/ - -#include - - -#include "../src/messaging/callback.hpp" -#include "../src/messaging/default_cb.hpp" -#include "../src/messaging/message.hpp" -#include "../src/messaging/messenger.hpp" -#include "../src/messaging/msg_component.hpp" -#include "../src/xapp/xapp.hpp" - -#include "../src/messaging/callback.cpp" -#include "../src/messaging/default_cb.cpp" -#include "../src/messaging/message.cpp" -#include "../src/messaging/messenger.cpp" -#include "../src/xapp/xapp.cpp" - -/* - callback error counts are global for ease. They track the number of times each callback - was invoked with the expected message type(s) and any times they were not. -*/ -int err_cb1 = 0; -int err_cb2 = 0; -int err_cbd = 0; - -int good_cb1 = 0; -int good_cb2 = 0; -int good_cbd = 0; - -/* - callback functions to register; driven as we "receive" messages (the RMR emulation package - will generate a message every time the receive function is called). -*/ -void cb1( Message& mbuf, int mtype, int subid, int len, Msg_component payload, void* data ) { - if( mtype != 1 ) { // should only be driven for type 1 messages - err_cb1++; - } else { - good_cb1++; - } -} -void cb2( Message& mbuf, int mtype, int subid, int len, Msg_component payload, void* data ) { - if( mtype != 2 ) { // should only be driven for type 2 messages - err_cb2++; - } else { - good_cb2++; - } -} -void cbd( Message& mbuf, int mtype, int subid, int len, Msg_component payload, void* data ) { - if( mtype > 0 && mtype < 3 ) { // should only be driven for types that arent 1 or 2 - if( err_cbd < 10 ) { - fprintf( stderr, " cbd: bad message type: %d\n", mtype ); - } - err_cbd++; - } else { - good_cbd++; - } -} - -/* - The Xapp Run() function only returns when Xapp is asked to stop, and that - isn't supported from inside any of the callbacks. This funciton is - started in a thread and after a few seconds it will drive the halt - function in the Xapp instance to stop the run function and allow the - unit test to finish. -*/ -void killer( std::shared_ptr x ) { - fprintf( stderr, " killer is waiting in the shadows\n" ); - sleep( 2 ); - fprintf( stderr, " killer is on the loose\n" ); - x->Halt(); -} - -int main( int argc, char** argv ) { - std::thread* tinfo; // we'll start a thread that will shut things down after a few seconds - std::unique_ptr msg; - std::shared_ptr x; - Msg_component payload; - std::unique_ptr ucs; - unsigned char* new_payload; - std::shared_ptr new_p_ref; // reference to payload to pass to send functions - char* port = (char *) "4560"; - int ai = 1; // arg processing index - int nthreads = 2; // ensure the for loop is executed in setup - int i; - int len; - int errors = 0; - char wbuf[256]; - - ai = 1; - while( ai < argc ) { // very simple flag processing (no bounds/error checking) - if( argv[ai][0] != '-' ) { - break; - } - - switch( argv[ai][1] ) { // we only support -x so -xy must be -x -y - case 'p': - port = argv[ai+1]; - ai++; - break; - - case 't': - nthreads = atoi( argv[ai+1] ); - ai++; - break; - } - - ai++; - } - - x = std::shared_ptr( new Xapp( port, true ) ); - x->Add_msg_cb( 1, cb1, NULL ); - x->Add_msg_cb( 2, cb2, NULL ); - x->Add_msg_cb( -1, cbd, NULL ); - - msg = x->Alloc_msg( 2048 ); - payload = msg->Get_payload(); - msg->Set_len( 128 ); - msg->Set_mtype( 100 ); - msg->Set_subid( -10 ); - - ucs = msg->Copy_payload( ); - if( ucs == NULL ) { - fprintf( stderr, " expected pointer to copy payload but got nil\n" ); - errors++; - } - - ucs = msg->Get_meid(); - if( ucs == NULL ) { - fprintf( stderr, " expected pointer to meid copy but got nil\n" ); - errors++; - } - - ucs = msg->Get_src(); - if( ucs == NULL ) { - fprintf( stderr, " expected pointer to src copy but got nil\n" ); - errors++; - } - - i = msg->Get_available_size(); - if( i != 2048 ) { - fprintf( stderr, " len expected payload avail size of 2048 but got %d\n", i ); - errors++; - } - - i = msg->Get_mtype(); - if( i != 100 ) { - fprintf( stderr, " expected mtype of 100 but got %d\n", i ); - errors++; - } - - i = msg->Get_state( ); - if( i != 0 ) { - fprintf( stderr, " expected state of 0 but got %d\n", i ); - errors++; - } - - i = msg->Get_subid(); - if( i != -10 ) { - fprintf( stderr, " expected subid of -10 but got %d\n", i ); - errors++; - } - - i = msg->Get_len(); - if( i != 128 ) { - fprintf( stderr, " len expected 128 but got %d\n", i ); - errors++; - } - - msg->Send(); // generic send as is functions - msg->Reply(); - - new_payload = (unsigned char *) malloc( sizeof( unsigned char ) * 2048 ); // a large payload - memset( new_payload, 0 , sizeof( unsigned char ) * 2048 ); - new_p_ref = std::shared_ptr( new_payload ); // reference it for send calls - - msg->Set_meid( new_p_ref ); - - msg->Send_msg( 255, new_p_ref ); // send without changing the message type/subid from above - msg->Send_msg( 255, new_payload ); // drive the alternate prototype - msg->Send_msg( 100, 1, 128, new_p_ref ); // send using just 128 bytes of payload - msg->Send_msg( 100, 1, 128, new_payload ); // drive with alternate prototype - - msg->Set_len( 128 ); - msg->Set_mtype( 100 ); - msg->Set_subid( -10 ); - - msg->Send_response( 100, new_p_ref ); // send a response (rts) with establisehd message type etc - msg->Send_response( 100, new_payload ); - msg->Send_response( 100, 10, 100, new_p_ref ); - msg->Send_response( 100, 10, 100, new_payload ); - - - msg = NULL; // should drive the message destroyer for coverage - - msg = x->Receive( 2000 ); - if( msg == NULL ) { - fprintf( stderr, " expected message from receive but got nil\n" ); - errors++; - } - - tinfo = new std::thread; // start killer thread to terminate things so that run doesn't hang forever - tinfo = new std::thread( killer, x ); - - x->Run( nthreads ); - x->Halt(); // drive for coverage - - if( err_cb1 + err_cb2 + err_cbd > 0 ) { - fprintf( stderr, " one or more callbacks reported an error: [%d] [%d] [%d]\n", err_cb1, err_cb2, err_cbd ); - fprintf( stderr, " callback good values: [%d] [%d] [%d]\n", good_cb1, good_cb2, good_cbd ); - errors++; - } - - // ----- specific move/copy coverage drivers --------------------------- - - Messenger m1( (char *) "1234", false ); // messenger class does NOT permit copies, so no need to test - Messenger m2( (char *) "9999", false ); - m1 = std::move( m2 ); // drives move operator= function - Messenger m3 = std::move( m1 ); // drives move constructor function - - std::unique_ptr msg2 = x->Alloc_msg( 2048 ); - std::unique_ptr msg3 = x->Alloc_msg( 4096 ); - - snprintf( wbuf, sizeof( wbuf ), "Stand up and cheer!!" ); - msg3->Set_len( strlen( wbuf ) ); - strcpy( (char *) (msg3->Get_payload()).get(), wbuf ); // populate the payload to vet copy later - fprintf( stderr, " set string (%s) \n", (char *) (msg3->Get_payload()).get() ); - - Message msg4 = *(msg3.get()); // drive copy builder; msg4 should have a 4096 byte payload - fprintf( stderr, " copy string (%s) \n", (char *) (msg4.Get_payload()).get() ); // and payload should be coppied - if( msg4.Get_available_size() != 4096 ) { - errors++; - fprintf( stderr, " message copy builder payload size smells: expected 4096, got %d\n", msg4.Get_available_size() ); - } - if( strcmp( (char *) msg4.Get_payload().get(), wbuf ) != 0 ) { - errors++; - fprintf( stderr, " message copy builder payload of copy not the expected string\n" ); - } - - snprintf( wbuf, sizeof( wbuf ), "Rambling Wreck; GT!" ); // different string into msg 2 to ensure copy replaced msg3 string - strcpy( (char *) (msg2->Get_payload()).get(), wbuf ); // populate the msg2 payload to vet copy - msg2->Set_len( strlen( wbuf ) ); - *msg3 = *msg2; // drive the copy operator= function - if( msg3->Get_available_size() != 2048 ) { - errors++; - fprintf( stderr, " message copy operator payload size smells: expected 2048, got %d\n", msg3->Get_available_size() ); - } - if( strcmp( (char *) msg3->Get_payload().get(), wbuf ) != 0 ) { - errors++; - fprintf( stderr, " message copy builder payload of copy not the expected string\n" ); - } - - Message msg5 = std::move( *(msg3.get()) ); // drive move constructor - if( msg5.Get_available_size() != 2048 ) { - errors++; - fprintf( stderr, " message copy operator payload size smells: expected 2048, got %d\n", msg5.Get_available_size() ); - } - if( strcmp( (char *) msg5.Get_payload().get(), wbuf ) != 0 ) { - errors++; - fprintf( stderr, " message copy builder payload of copy not the expected string\n" ); - } - - msg5.Set_len( 2 ); // bogus len for vetting later - msg5 = std::move( *(msg3.get()) ); - if( msg5.Get_len() == 21 ) { - errors++; - fprintf( stderr, " message move operator payload len smells: expected 21, got %d\n", msg5.Get_len() ); - } - - return errors > 0; -} diff --git a/test/unit_test.sh b/test/unit_test.sh index 7144f9c..d361fb7 100755 --- a/test/unit_test.sh +++ b/test/unit_test.sh @@ -63,18 +63,24 @@ spew="cat" # default to dumping all make output on failure (-q turns it to ~ while [[ $1 == "-"* ]] do case $1 in - -q) spew="head -40";; + -q) spew="head -40";; # how much to dump on build error -v) spew="cat";; esac shift done +if [[ ! -f unit_test.cpp ]] +then + echo "[PASS] no unit test source exists" + exit 0 +fi + make nuke >/dev/null make unit_test >/tmp/PID$$.log 2>&1 abort_if_error $? "unable to make" -spew="cat" +spew="cat" # after we build, dump everything on error ./unit_test >/tmp/PID$$.log 2>&1 abort_if_error $? "unit test failed" diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..7a1ec97 --- /dev/null +++ b/tox.ini @@ -0,0 +1,37 @@ +# This work is licensed under a Creative Commons Attribution 4.0 International License. +# SPDX-License-Identifier: CC-BY-4.0 +# Copyright (C) 2020 AT&T Intellectual Property +# documentation only + +# this file is needed to control the read the docs verification mechanism in jenkins + +[tox] +minversion = 2.0 +envlist = + docs, + docs-linkcheck, +skipsdist = true + +[testenv:docs] +basepython = python3 +deps = + sphinx + sphinx-rtd-theme + sphinxcontrib-httpdomain + recommonmark + lfdocs-conf + +commands = + sphinx-build -W -b html -n -d {envtmpdir}/doctrees ./docs/ {toxinidir}/docs/_build/html + echo "Generated docs available in {toxinidir}/docs/_build/html" +whitelist_externals = echo + +[testenv:docs-linkcheck] +basepython = python3 +deps = sphinx + sphinx-rtd-theme + sphinxcontrib-httpdomain + recommonmark + lfdocs-conf +commands = sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees ./docs/ {toxinidir}/docs/_build/linkcheck + -- 2.16.6