From 4c9f1d6ff2bd6ef4ab79327809c0e74f3db74238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Poderoso?= <120394830+JesusPoderoso@users.noreply.github.com> Date: Thu, 27 Jun 2024 15:20:52 +0200 Subject: [PATCH] Examples refactor: Delivery mechanisms (#4959) * Refs #20650: Implement Delivery mechanisms example Signed-off-by: JesusPoderoso * Refs #20650: Generate types with latest gen version Signed-off-by: JesusPoderoso * Refs #20650: Write example README and versions.md Signed-off-by: JesusPoderoso * Refs #20650: Add example tests Signed-off-by: JesusPoderoso * Refs #20650: Apply rev suggestions Signed-off-by: JesusPoderoso * Refs #20650: Please linter Signed-off-by: JesusPoderoso * Refs #20650: Apply rev suggestions and fix test Signed-off-by: JesusPoderoso * Refs #20650: Adjust timeouts Signed-off-by: JesusPoderoso * Refs #20650: Add missing configurations that were lost in the review Signed-off-by: JesusPoderoso * Refs #20650: Proper configuration for initial peers Signed-off-by: JesusPoderoso * Refs #20650: Set pubsub tcp as unsupported cornercase Signed-off-by: JesusPoderoso * Refs #20650: Include publisher tests Signed-off-by: JesusPoderoso * Refs #20650: Adapt pubsub stop condition when both pub and sub have really stopped Signed-off-by: JesusPoderoso * Refs #20650: Adapt tests Signed-off-by: JesusPoderoso * Refs #20650: Regenerate types with latest changes in fastdds / fastdds gen Signed-off-by: JesusPoderoso * Refs #20650: Include license in test files Signed-off-by: JesusPoderoso * Refs #20650: Apply THE fix Signed-off-by: JesusPoderoso * Refs #20650: Add type constraints check in each app Signed-off-by: JesusPoderoso * Refs #20650: Add missing mechanisms: UDPv6, TCPv6 and large data Signed-off-by: JesusPoderoso * Refs #20650: Update the tests with new meachanisms Signed-off-by: JesusPoderoso * Refs #20650: Add address argument and usage Signed-off-by: JesusPoderoso * Refs #20650: Add isolated examples Signed-off-by: JesusPoderoso * Refs #20650: Apply rev suggestions Signed-off-by: JesusPoderoso * Refs #20650: Please linter Signed-off-by: JesusPoderoso * Refs #20650: Apply rev suggestions (2) Signed-off-by: JesusPoderoso --------- Signed-off-by: JesusPoderoso --- examples/CMakeLists.txt | 1 + .../cpp/delivery_mechanisms/Application.cpp | 62 +++ .../cpp/delivery_mechanisms/Application.hpp | 56 +++ .../cpp/delivery_mechanisms/CLIParser.hpp | 418 ++++++++++++++++++ .../cpp/delivery_mechanisms/CMakeLists.txt | 46 ++ .../DeliveryMechanisms.hpp | 226 ++++++++++ .../DeliveryMechanisms.idl | 6 + .../DeliveryMechanismsCdrAux.hpp | 46 ++ .../DeliveryMechanismsCdrAux.ipp | 126 ++++++ .../DeliveryMechanismsPubSubTypes.cxx | 229 ++++++++++ .../DeliveryMechanismsPubSubTypes.hpp | 188 ++++++++ .../DeliveryMechanismsTypeObjectSupport.cxx | 171 +++++++ .../DeliveryMechanismsTypeObjectSupport.hpp | 56 +++ .../cpp/delivery_mechanisms/PubSubApp.cpp | 418 ++++++++++++++++++ .../cpp/delivery_mechanisms/PubSubApp.hpp | 121 +++++ .../cpp/delivery_mechanisms/PublisherApp.cpp | 313 +++++++++++++ .../cpp/delivery_mechanisms/PublisherApp.hpp | 100 +++++ examples/cpp/delivery_mechanisms/README.md | 147 ++++++ .../cpp/delivery_mechanisms/SubscriberApp.cpp | 296 +++++++++++++ .../cpp/delivery_mechanisms/SubscriberApp.hpp | 100 +++++ examples/cpp/delivery_mechanisms/main.cpp | 96 ++++ test/examples/delivery_mechanisms.compose.yml | 61 +++ .../delivery_mechanisms_isolated.compose.yml | 76 ++++ test/examples/test_configuration.py | 5 +- test/examples/test_delivery_mechanisms.py | 159 +++++++ .../test_delivery_mechanisms_isolated.py | 146 ++++++ test/examples/test_hello_world.py | 2 +- versions.md | 1 + 28 files changed, 3669 insertions(+), 3 deletions(-) create mode 100644 examples/cpp/delivery_mechanisms/Application.cpp create mode 100644 examples/cpp/delivery_mechanisms/Application.hpp create mode 100644 examples/cpp/delivery_mechanisms/CLIParser.hpp create mode 100644 examples/cpp/delivery_mechanisms/CMakeLists.txt create mode 100644 examples/cpp/delivery_mechanisms/DeliveryMechanisms.hpp create mode 100644 examples/cpp/delivery_mechanisms/DeliveryMechanisms.idl create mode 100644 examples/cpp/delivery_mechanisms/DeliveryMechanismsCdrAux.hpp create mode 100644 examples/cpp/delivery_mechanisms/DeliveryMechanismsCdrAux.ipp create mode 100644 examples/cpp/delivery_mechanisms/DeliveryMechanismsPubSubTypes.cxx create mode 100644 examples/cpp/delivery_mechanisms/DeliveryMechanismsPubSubTypes.hpp create mode 100644 examples/cpp/delivery_mechanisms/DeliveryMechanismsTypeObjectSupport.cxx create mode 100644 examples/cpp/delivery_mechanisms/DeliveryMechanismsTypeObjectSupport.hpp create mode 100644 examples/cpp/delivery_mechanisms/PubSubApp.cpp create mode 100644 examples/cpp/delivery_mechanisms/PubSubApp.hpp create mode 100644 examples/cpp/delivery_mechanisms/PublisherApp.cpp create mode 100644 examples/cpp/delivery_mechanisms/PublisherApp.hpp create mode 100644 examples/cpp/delivery_mechanisms/README.md create mode 100644 examples/cpp/delivery_mechanisms/SubscriberApp.cpp create mode 100644 examples/cpp/delivery_mechanisms/SubscriberApp.hpp create mode 100644 examples/cpp/delivery_mechanisms/main.cpp create mode 100644 test/examples/delivery_mechanisms.compose.yml create mode 100644 test/examples/delivery_mechanisms_isolated.compose.yml create mode 100644 test/examples/test_delivery_mechanisms.py create mode 100644 test/examples/test_delivery_mechanisms_isolated.py diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index de35eb6c149..03b1517abf4 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -18,6 +18,7 @@ add_subdirectory(cpp/configuration) add_subdirectory(cpp/content_filter) add_subdirectory(cpp/custom_payload_pool) add_subdirectory(cpp/dds) +add_subdirectory(cpp/delivery_mechanisms) add_subdirectory(cpp/hello_world) add_subdirectory(cpp/rtps) add_subdirectory(cpp/xtypes) diff --git a/examples/cpp/delivery_mechanisms/Application.cpp b/examples/cpp/delivery_mechanisms/Application.cpp new file mode 100644 index 00000000000..ab87cf2ed3b --- /dev/null +++ b/examples/cpp/delivery_mechanisms/Application.cpp @@ -0,0 +1,62 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 Application.cpp + * + */ + +#include "Application.hpp" + +#include "CLIParser.hpp" +#include "PublisherApp.hpp" +#include "SubscriberApp.hpp" +#include "PubSubApp.hpp" + +using namespace eprosima::fastdds::dds; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace delivery_mechanisms { + +//! Factory method to create a publisher or subscriber +std::shared_ptr Application::make_app( + const CLIParser::delivery_mechanisms_config& config, + const std::string& topic_name) +{ + std::shared_ptr entity; + switch (config.entity) + { + case CLIParser::EntityKind::PUBLISHER: + entity = std::make_shared(config, topic_name); + break; + case CLIParser::EntityKind::SUBSCRIBER: + entity = std::make_shared(config, topic_name); + break; + case CLIParser::EntityKind::PUBSUB: + entity = std::make_shared(config, topic_name); + break; + case CLIParser::EntityKind::UNDEFINED: + default: + throw std::runtime_error("Entity initialization failed"); + break; + } + return entity; +} + +} // namespace delivery_mechanisms +} // namespace examples +} // namespace fastdds +} // namespace eprosima diff --git a/examples/cpp/delivery_mechanisms/Application.hpp b/examples/cpp/delivery_mechanisms/Application.hpp new file mode 100644 index 00000000000..5977ab444e9 --- /dev/null +++ b/examples/cpp/delivery_mechanisms/Application.hpp @@ -0,0 +1,56 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 Application.hpp + * + */ + +#ifndef _FASTDDS_DELIVERY_MECHANISMS_APPLICATION_HPP_ +#define _FASTDDS_DELIVERY_MECHANISMS_APPLICATION_HPP_ + +#include + +#include "CLIParser.hpp" + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace delivery_mechanisms { + +class Application +{ +public: + + //! Virtual destructor + virtual ~Application() = default; + + //! Run application + virtual void run() = 0; + + //! Trigger the end of execution + virtual void stop() = 0; + + //! Factory method to create applications based on configuration + static std::shared_ptr make_app( + const CLIParser::delivery_mechanisms_config& config, + const std::string& topic_name); +}; + +} // namespace delivery_mechanisms +} // namespace examples +} // namespace fastdds +} // namespace eprosima + +#endif /* _FASTDDS_DELIVERY_MECHANISMS_APPLICATION_HPP_ */ diff --git a/examples/cpp/delivery_mechanisms/CLIParser.hpp b/examples/cpp/delivery_mechanisms/CLIParser.hpp new file mode 100644 index 00000000000..5796491847a --- /dev/null +++ b/examples/cpp/delivery_mechanisms/CLIParser.hpp @@ -0,0 +1,418 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 +#include +#include + +#include +#include +#include + +#ifndef _FASTDDS_DELIVERY_MECHANISMS_CLI_PARSER_HPP_ +#define _FASTDDS_DELIVERY_MECHANISMS_CLI_PARSER_HPP_ + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace delivery_mechanisms { + +using namespace eprosima::fastdds::dds; +using dds::Log; + +class CLIParser +{ +public: + + CLIParser() = delete; + + //! Entity kind enumeration + enum class EntityKind : uint8_t + { + PUBLISHER, + SUBSCRIBER, + PUBSUB, + UNDEFINED + }; + + //! Delivery mechanism enumeration + enum class DeliveryMechanismKind : uint8_t + { + DATA_SHARING, + INTRA_PROCESS, + LARGE_DATA, + SHM, + TCPv4, + TCPv6, + UDPv4, + UDPv6, + DEFAULT + }; + + //! DeliveryMechanisms structure for the application + struct delivery_mechanisms_config + { + CLIParser::EntityKind entity = CLIParser::EntityKind::UNDEFINED; + bool ignore_local_endpoints = false; + uint16_t samples = 0; + uint32_t domain = 0; + DeliveryMechanismKind delivery_mechanism = DeliveryMechanismKind::DEFAULT; + std::string tcp_ip_address = ""; + }; + + /** + * @brief Print usage help message and exit with the given return code + * + * @param return_code return code to exit with + * + * @warning This method finishes the execution of the program with the input return code + */ + static void print_help( + uint8_t return_code) + { + std::cout << "Usage: delivery_mechanisms [options]" << std::endl; + std::cout << "" << std::endl; + std::cout << "Entities:" << std::endl; + std::cout << " publisher Run a publisher entity" << std::endl; + std::cout << " subscriber Run a subscriber entity" << std::endl; + std::cout << " pubsub Run both publisher and subscriber entities" << std::endl; + std::cout << " in the same participant" << std::endl; + std::cout << "" << std::endl; + std::cout << "Common options:" << std::endl; + std::cout << " -a , --address TCP IP address (only available if selected" << std::endl; + std::cout << " delivery mechanism is TCPv4 or TCPv6)" << std::endl; + std::cout << " (Default: localhost [127.0.0.1 or ::1])" << std::endl; + std::cout << " -d , --domain Domain ID number [0 <= <= 232]" << std::endl; + std::cout << " (Default: 0)" << std::endl; + std::cout << " -h, --help Print this help message" << std::endl; + std::cout << " -m , --mechanism Select delivery mechanism :" << std::endl; + std::cout << " · DATA-SHARING: Data-sharing mechanism" << std::endl; + std::cout << " · INTRA-PROCESS: Intra-process mechanism" << std::endl; + std::cout << " (only allowed with \"pubsub\" entity)" << std::endl; + std::cout << " · LARGE-DATA: Large data mechanism" << std::endl; + std::cout << " · TCPv4: TCP transport over IPv4" << std::endl; + std::cout << " · TCPv6: TCP transport over IPv6" << std::endl; + std::cout << " · UDPv4: UDP transport over IPv4" << std::endl; + std::cout << " · UDPv6: UDP transport over IPv6" << std::endl; + std::cout << " · SHM: Shared Memory Transport" << std::endl; + std::cout << " (Default: default builtin transports" << std::endl; + std::cout << " [SHM and UDPv4, SHM prior UDPv4])" << std::endl; + std::cout << " -s , --samples Number of samples to send or receive" << std::endl; + std::cout << " [0 <= <= 65535]" << std::endl; + std::cout << " (Default: 0 [unlimited])" << std::endl; + std::cout << "" << std::endl; + std::cout << "\"pubsub\" options:" << std::endl; + std::cout << " -i , --ignore-local-endpoints Avoid matching compatible datareaders and" << std::endl; + std::cout << " datawriters that belong to the same domain" << std::endl; + std::cout << " participant" << std::endl; + std::cout << " Default(false [they match])" << std::endl; + std::exit(return_code); + } + + /** + * @brief Parse the command line options and return the delivery_mechanisms_config object + * + * @param argc number of arguments + * @param argv array of arguments + * @return delivery_mechanisms_config object with the parsed options + * + * @warning This method finishes the execution of the program if the input arguments are invalid + */ + static delivery_mechanisms_config parse_cli_options( + int argc, + char* argv[]) + { + delivery_mechanisms_config config; + + if (argc < 2) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "missing entity argument"); + print_help(EXIT_FAILURE); + } + + std::string first_argument = argv[1]; + + if (first_argument == "publisher" ) + { + config.entity = CLIParser::EntityKind::PUBLISHER; + } + else if ( first_argument == "subscriber") + { + config.entity = CLIParser::EntityKind::SUBSCRIBER; + } + else if ( first_argument == "pubsub") + { + config.entity = CLIParser::EntityKind::PUBSUB; + } + else if (first_argument == "-h" || first_argument == "--help") + { + print_help(EXIT_SUCCESS); + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing entity argument " + first_argument); + print_help(EXIT_FAILURE); + } + + for (int i = 2; i < argc; ++i) + { + std::string arg = argv[i]; + + if (arg == "-h" || arg == "--help") + { + print_help(EXIT_SUCCESS); + } + else if (arg == "-a" || arg == "--address") + { + if (++i < argc) + { + config.tcp_ip_address = argv[i]; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing address argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-d" || arg == "--domain") + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < 0 || input > 232) + { + throw std::out_of_range("domain argument " + std::string( + argv[i]) + " out of range [0, 232]."); + } + else + { + config.domain = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid domain argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing domain argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-s" || arg == "--samples") + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < std::numeric_limits::min() || + input > std::numeric_limits::max()) + { + throw std::out_of_range("sample argument " + std::string( + argv[i]) + " out of range [0, 65535]."); + } + else + { + config.samples = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid sample argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing samples argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-m" || arg == "--mechanism") + { + if (++i < argc) + { + std::string mechanism = argv[i]; + if (mechanism == "DATA-SHARING" || mechanism == "data-sharing" + || mechanism == "DATA_SHARING" || mechanism == "data_sharing") + { + config.delivery_mechanism = DeliveryMechanismKind::DATA_SHARING; + } + else if (mechanism == "INTRA-PROCESS" || mechanism == "intra-process" + || mechanism == "INTRA_PROCESS" || mechanism == "intra_process") + { + if (config.entity == EntityKind::PUBSUB) + { + config.delivery_mechanism = DeliveryMechanismKind::INTRA_PROCESS; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, + "intra-process mechanism only allowed with \"pubsub\" entity"); + print_help(EXIT_FAILURE); + } + } + else if (mechanism == "LARGE-DATA" || mechanism == "large-data" + || mechanism == "LARGE_DATA" || mechanism == "large_data") + { + config.delivery_mechanism = DeliveryMechanismKind::LARGE_DATA; + } + else if (mechanism == "TCP" || mechanism == "tcp" || mechanism == "TCPv4" || mechanism == "tcpv4" + || mechanism == "TCPV4") + { + config.delivery_mechanism = DeliveryMechanismKind::TCPv4; + } + else if (mechanism == "TCPv6" || mechanism == "tcpv6" || mechanism == "TCPV6") + { + config.delivery_mechanism = DeliveryMechanismKind::TCPv6; + } + else if (mechanism == "UDP" || mechanism == "udp" || mechanism == "UDPv4" || mechanism == "udpv4" + || mechanism == "UDPV4") + { + config.delivery_mechanism = DeliveryMechanismKind::UDPv4; + } + else if (mechanism == "UDPv6" || mechanism == "udpv6" || mechanism == "UDPV6") + { + config.delivery_mechanism = DeliveryMechanismKind::UDPv6; + } + else if (mechanism == "SHM" || mechanism == "shm") + { + config.delivery_mechanism = DeliveryMechanismKind::SHM; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing mechanism argument"); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing mechanism argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-i" || arg == "--ignore-local-endpoints") + { + if (config.entity == EntityKind::PUBSUB) + { + config.ignore_local_endpoints = true; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "ignore-local-endpoints option only allowed with \"pubsub\" entity"); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing argument: " + arg); + print_help(EXIT_FAILURE); + } + } + + // Pubsub entity does not support TCP transport without ignore-local-endpoints option + if (config.entity == CLIParser::EntityKind::PUBSUB && !config.ignore_local_endpoints && + (config.delivery_mechanism == DeliveryMechanismKind::TCPv4 || + config.delivery_mechanism == DeliveryMechanismKind::TCPv6)) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, + "Unsupported corner case: TCP delivery mechanism is not allowed for \"pubsub\" without ignore-local-endpoints option"); + print_help(EXIT_FAILURE); + } + + // Address argument is only allowed with TCP transport + if (!config.tcp_ip_address.empty() && + !(config.delivery_mechanism == DeliveryMechanismKind::TCPv4 || + config.delivery_mechanism == DeliveryMechanismKind::TCPv6)) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "address argument only allowed with TCP delivery mechanism"); + print_help(EXIT_FAILURE); + } + return config; + } + + /** + * @brief Parse the signal number into the signal name + * + * @param signum signal number + * @return std::string signal name + */ + static std::string parse_signal( + const int& signum) + { + switch (signum) + { + case SIGINT: + return "SIGINT"; + case SIGTERM: + return "SIGTERM"; +#ifndef _WIN32 + case SIGQUIT: + return "SIGQUIT"; + case SIGHUP: + return "SIGHUP"; +#endif // _WIN32 + default: + return "UNKNOWN SIGNAL"; + } + } + + /** + * @brief Parse the entity kind into std::string + * + * @param entity entity kind + * @return std::string entity kind + */ + static std::string parse_entity_kind( + const EntityKind& entity) + { + switch (entity) + { + case EntityKind::PUBLISHER: + return "Publisher"; + case EntityKind::SUBSCRIBER: + return "Subscriber"; + case EntityKind::PUBSUB: + return "PubSub"; + case EntityKind::UNDEFINED: + default: + return "Undefined entity"; + } + } + +}; + +} // namespace delivery_mechanisms +} // namespace examples +} // namespace fastdds +} // namespace eprosima + +#endif // _FASTDDS_DELIVERY_MECHANISMS_CLI_PARSER_HPP_ diff --git a/examples/cpp/delivery_mechanisms/CMakeLists.txt b/examples/cpp/delivery_mechanisms/CMakeLists.txt new file mode 100644 index 00000000000..4f08f91d614 --- /dev/null +++ b/examples/cpp/delivery_mechanisms/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# 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. + +cmake_minimum_required(VERSION 3.20) + +project(fastdds_delivery_mechanisms_example VERSION 1 LANGUAGES CXX) + +# Find requirements +if(NOT fastcdr_FOUND) + find_package(fastcdr 2 REQUIRED) +endif() + +if(NOT fastdds_FOUND) + find_package(fastdds 3 REQUIRED) +endif() + +#Check C++11 +include(CheckCXXCompilerFlag) +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + check_cxx_compiler_flag(-std=c++11 SUPPORTS_CXX11) + if(NOT SUPPORTS_CXX11) + message(FATAL_ERROR "Compiler doesn't support C++11") + endif() +endif() + +message(STATUS "Configuring delivery mechanisms example...") +file(GLOB DELIVERY_MECHANISMS_SOURCES_CXX "*.cxx") +file(GLOB DELIVERY_MECHANISMS_SOURCES_CPP "*.cpp") + +add_executable(delivery_mechanisms + ${DELIVERY_MECHANISMS_SOURCES_CXX} + ${DELIVERY_MECHANISMS_SOURCES_CPP}) +target_link_libraries(delivery_mechanisms fastdds fastcdr) +install(TARGETS delivery_mechanisms + RUNTIME DESTINATION examples/cpp/delivery_mechanisms/${BIN_INSTALL_DIR}) diff --git a/examples/cpp/delivery_mechanisms/DeliveryMechanisms.hpp b/examples/cpp/delivery_mechanisms/DeliveryMechanisms.hpp new file mode 100644 index 00000000000..132b122ab01 --- /dev/null +++ b/examples/cpp/delivery_mechanisms/DeliveryMechanisms.hpp @@ -0,0 +1,226 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 DeliveryMechanisms.hpp + * This header file contains the declaration of the described types in the IDL file. + * + * This file was generated by the tool fastddsgen. + */ + +#ifndef FAST_DDS_GENERATED__DELIVERYMECHANISMS_HPP +#define FAST_DDS_GENERATED__DELIVERYMECHANISMS_HPP + +#include +#include +#include + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#define eProsima_user_DllExport __declspec( dllexport ) +#else +#define eProsima_user_DllExport +#endif // EPROSIMA_USER_DLL_EXPORT +#else +#define eProsima_user_DllExport +#endif // _WIN32 + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#if defined(DELIVERYMECHANISMS_SOURCE) +#define DELIVERYMECHANISMS_DllAPI __declspec( dllexport ) +#else +#define DELIVERYMECHANISMS_DllAPI __declspec( dllimport ) +#endif // DELIVERYMECHANISMS_SOURCE +#else +#define DELIVERYMECHANISMS_DllAPI +#endif // EPROSIMA_USER_DLL_EXPORT +#else +#define DELIVERYMECHANISMS_DllAPI +#endif // _WIN32 + +/*! + * @brief This class represents the structure DeliveryMechanisms defined by the user in the IDL file. + * @ingroup DeliveryMechanisms + */ +class DeliveryMechanisms +{ +public: + + /*! + * @brief Default constructor. + */ + eProsima_user_DllExport DeliveryMechanisms() + { + } + + /*! + * @brief Default destructor. + */ + eProsima_user_DllExport ~DeliveryMechanisms() + { + } + + /*! + * @brief Copy constructor. + * @param x Reference to the object DeliveryMechanisms that will be copied. + */ + eProsima_user_DllExport DeliveryMechanisms( + const DeliveryMechanisms& x) + { + m_index = x.m_index; + + m_message = x.m_message; + + } + + /*! + * @brief Move constructor. + * @param x Reference to the object DeliveryMechanisms that will be copied. + */ + eProsima_user_DllExport DeliveryMechanisms( + DeliveryMechanisms&& x) noexcept + { + m_index = x.m_index; + m_message = std::move(x.m_message); + } + + /*! + * @brief Copy assignment. + * @param x Reference to the object DeliveryMechanisms that will be copied. + */ + eProsima_user_DllExport DeliveryMechanisms& operator =( + const DeliveryMechanisms& x) + { + + m_index = x.m_index; + + m_message = x.m_message; + + return *this; + } + + /*! + * @brief Move assignment. + * @param x Reference to the object DeliveryMechanisms that will be copied. + */ + eProsima_user_DllExport DeliveryMechanisms& operator =( + DeliveryMechanisms&& x) noexcept + { + + m_index = x.m_index; + m_message = std::move(x.m_message); + return *this; + } + + /*! + * @brief Comparison operator. + * @param x DeliveryMechanisms object to compare. + */ + eProsima_user_DllExport bool operator ==( + const DeliveryMechanisms& x) const + { + return (m_index == x.m_index && + m_message == x.m_message); + } + + /*! + * @brief Comparison operator. + * @param x DeliveryMechanisms object to compare. + */ + eProsima_user_DllExport bool operator !=( + const DeliveryMechanisms& x) const + { + return !(*this == x); + } + + /*! + * @brief This function sets a value in member index + * @param _index New value for member index + */ + eProsima_user_DllExport void index( + uint32_t _index) + { + m_index = _index; + } + + /*! + * @brief This function returns the value of member index + * @return Value of member index + */ + eProsima_user_DllExport uint32_t index() const + { + return m_index; + } + + /*! + * @brief This function returns a reference to member index + * @return Reference to member index + */ + eProsima_user_DllExport uint32_t& index() + { + return m_index; + } + + + /*! + * @brief This function copies the value in member message + * @param _message New value to be copied in member message + */ + eProsima_user_DllExport void message( + const std::array& _message) + { + m_message = _message; + } + + /*! + * @brief This function moves the value in member message + * @param _message New value to be moved in member message + */ + eProsima_user_DllExport void message( + std::array&& _message) + { + m_message = std::move(_message); + } + + /*! + * @brief This function returns a constant reference to member message + * @return Constant reference to member message + */ + eProsima_user_DllExport const std::array& message() const + { + return m_message; + } + + /*! + * @brief This function returns a reference to member message + * @return Reference to member message + */ + eProsima_user_DllExport std::array& message() + { + return m_message; + } + + + +private: + + uint32_t m_index{0}; + std::array m_message{0}; + +}; + +#endif // _FAST_DDS_GENERATED_DELIVERYMECHANISMS_HPP_ + + diff --git a/examples/cpp/delivery_mechanisms/DeliveryMechanisms.idl b/examples/cpp/delivery_mechanisms/DeliveryMechanisms.idl new file mode 100644 index 00000000000..255d0e8e7c8 --- /dev/null +++ b/examples/cpp/delivery_mechanisms/DeliveryMechanisms.idl @@ -0,0 +1,6 @@ +@extensibility(FINAL) +struct DeliveryMechanisms +{ + unsigned long index; + char message[32]; +}; diff --git a/examples/cpp/delivery_mechanisms/DeliveryMechanismsCdrAux.hpp b/examples/cpp/delivery_mechanisms/DeliveryMechanismsCdrAux.hpp new file mode 100644 index 00000000000..c620004e0b3 --- /dev/null +++ b/examples/cpp/delivery_mechanisms/DeliveryMechanismsCdrAux.hpp @@ -0,0 +1,46 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 DeliveryMechanismsCdrAux.hpp + * This source file contains some definitions of CDR related functions. + * + * This file was generated by the tool fastddsgen. + */ + +#ifndef FAST_DDS_GENERATED__DELIVERYMECHANISMSCDRAUX_HPP +#define FAST_DDS_GENERATED__DELIVERYMECHANISMSCDRAUX_HPP + +#include "DeliveryMechanisms.hpp" + +constexpr uint32_t DeliveryMechanisms_max_cdr_typesize {36UL}; +constexpr uint32_t DeliveryMechanisms_max_key_cdr_typesize {0UL}; + + +namespace eprosima { +namespace fastcdr { + +class Cdr; +class CdrSizeCalculator; + +eProsima_user_DllExport void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const DeliveryMechanisms& data); + + +} // namespace fastcdr +} // namespace eprosima + +#endif // FAST_DDS_GENERATED__DELIVERYMECHANISMSCDRAUX_HPP + diff --git a/examples/cpp/delivery_mechanisms/DeliveryMechanismsCdrAux.ipp b/examples/cpp/delivery_mechanisms/DeliveryMechanismsCdrAux.ipp new file mode 100644 index 00000000000..b1d1cea6dcd --- /dev/null +++ b/examples/cpp/delivery_mechanisms/DeliveryMechanismsCdrAux.ipp @@ -0,0 +1,126 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 DeliveryMechanismsCdrAux.ipp + * This source file contains some declarations of CDR related functions. + * + * This file was generated by the tool fastddsgen. + */ + +#ifndef FAST_DDS_GENERATED__DELIVERYMECHANISMSCDRAUX_IPP +#define FAST_DDS_GENERATED__DELIVERYMECHANISMSCDRAUX_IPP + +#include "DeliveryMechanismsCdrAux.hpp" + +#include +#include + + +#include +using namespace eprosima::fastcdr::exception; + +namespace eprosima { +namespace fastcdr { + +template<> +eProsima_user_DllExport size_t calculate_serialized_size( + eprosima::fastcdr::CdrSizeCalculator& calculator, + const DeliveryMechanisms& data, + size_t& current_alignment) +{ + static_cast(data); + + eprosima::fastcdr::EncodingAlgorithmFlag previous_encoding = calculator.get_encoding(); + size_t calculated_size {calculator.begin_calculate_type_serialized_size( + eprosima::fastcdr::CdrVersion::XCDRv2 == calculator.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + current_alignment)}; + + + calculated_size += calculator.calculate_member_serialized_size(eprosima::fastcdr::MemberId(0), + data.index(), current_alignment); + + calculated_size += calculator.calculate_member_serialized_size(eprosima::fastcdr::MemberId(1), + data.message(), current_alignment); + + + calculated_size += calculator.end_calculate_type_serialized_size(previous_encoding, current_alignment); + + return calculated_size; +} + +template<> +eProsima_user_DllExport void serialize( + eprosima::fastcdr::Cdr& scdr, + const DeliveryMechanisms& data) +{ + eprosima::fastcdr::Cdr::state current_state(scdr); + scdr.begin_serialize_type(current_state, + eprosima::fastcdr::CdrVersion::XCDRv2 == scdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR); + + scdr + << eprosima::fastcdr::MemberId(0) << data.index() + << eprosima::fastcdr::MemberId(1) << data.message() +; + scdr.end_serialize_type(current_state); +} + +template<> +eProsima_user_DllExport void deserialize( + eprosima::fastcdr::Cdr& cdr, + DeliveryMechanisms& data) +{ + cdr.deserialize_type(eprosima::fastcdr::CdrVersion::XCDRv2 == cdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + [&data](eprosima::fastcdr::Cdr& dcdr, const eprosima::fastcdr::MemberId& mid) -> bool + { + bool ret_value = true; + switch (mid.id) + { + case 0: + dcdr >> data.index(); + break; + + case 1: + dcdr >> data.message(); + break; + + default: + ret_value = false; + break; + } + return ret_value; + }); +} + +void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const DeliveryMechanisms& data) +{ + static_cast(scdr); + static_cast(data); +} + + + +} // namespace fastcdr +} // namespace eprosima + +#endif // FAST_DDS_GENERATED__DELIVERYMECHANISMSCDRAUX_IPP + diff --git a/examples/cpp/delivery_mechanisms/DeliveryMechanismsPubSubTypes.cxx b/examples/cpp/delivery_mechanisms/DeliveryMechanismsPubSubTypes.cxx new file mode 100644 index 00000000000..1525521fa8b --- /dev/null +++ b/examples/cpp/delivery_mechanisms/DeliveryMechanismsPubSubTypes.cxx @@ -0,0 +1,229 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 DeliveryMechanismsPubSubTypes.cpp + * This header file contains the implementation of the serialization functions. + * + * This file was generated by the tool fastddsgen. + */ + +#include "DeliveryMechanismsPubSubTypes.hpp" + +#include +#include + +#include "DeliveryMechanismsCdrAux.hpp" +#include "DeliveryMechanismsTypeObjectSupport.hpp" + +using SerializedPayload_t = eprosima::fastdds::rtps::SerializedPayload_t; +using InstanceHandle_t = eprosima::fastdds::rtps::InstanceHandle_t; +using DataRepresentationId_t = eprosima::fastdds::dds::DataRepresentationId_t; + +DeliveryMechanismsPubSubType::DeliveryMechanismsPubSubType() +{ + setName("DeliveryMechanisms"); + uint32_t type_size = +#if FASTCDR_VERSION_MAJOR == 1 + static_cast(DeliveryMechanisms::getMaxCdrSerializedSize()); +#else + DeliveryMechanisms_max_cdr_typesize; +#endif + type_size += static_cast(eprosima::fastcdr::Cdr::alignment(type_size, 4)); /* possible submessage alignment */ + m_typeSize = type_size + 4; /*encapsulation*/ + m_isGetKeyDefined = false; + uint32_t keyLength = DeliveryMechanisms_max_key_cdr_typesize > 16 ? DeliveryMechanisms_max_key_cdr_typesize : 16; + m_keyBuffer = reinterpret_cast(malloc(keyLength)); + memset(m_keyBuffer, 0, keyLength); +} + +DeliveryMechanismsPubSubType::~DeliveryMechanismsPubSubType() +{ + if (m_keyBuffer != nullptr) + { + free(m_keyBuffer); + } +} + +bool DeliveryMechanismsPubSubType::serialize( + const void* const data, + SerializedPayload_t* payload, + DataRepresentationId_t data_representation) +{ + const DeliveryMechanisms* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload->data), payload->max_size); + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN, + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 : eprosima::fastcdr::CdrVersion::XCDRv2); + payload->encapsulation = ser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; +#if FASTCDR_VERSION_MAJOR > 1 + ser.set_encoding_flag( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR2); +#endif // FASTCDR_VERSION_MAJOR > 1 + + try + { + // Serialize encapsulation + ser.serialize_encapsulation(); + // Serialize the object. + ser << *p_type; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + // Get the serialized length +#if FASTCDR_VERSION_MAJOR == 1 + payload->length = static_cast(ser.getSerializedDataLength()); +#else + payload->length = static_cast(ser.get_serialized_data_length()); +#endif // FASTCDR_VERSION_MAJOR == 1 + return true; +} + +bool DeliveryMechanismsPubSubType::deserialize( + SerializedPayload_t* payload, + void* data) +{ + try + { + // Convert DATA to pointer of your type + DeliveryMechanisms* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload->data), payload->length); + + // Object that deserializes the data. + eprosima::fastcdr::Cdr deser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN +#if FASTCDR_VERSION_MAJOR == 1 + , eprosima::fastcdr::Cdr::CdrType::DDS_CDR +#endif // FASTCDR_VERSION_MAJOR == 1 + ); + + // Deserialize encapsulation. + deser.read_encapsulation(); + payload->encapsulation = deser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + + // Deserialize the object. + deser >> *p_type; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + return true; +} + +std::function DeliveryMechanismsPubSubType::getSerializedSizeProvider( + const void* const data, + DataRepresentationId_t data_representation) +{ + return [data, data_representation]() -> uint32_t + { +#if FASTCDR_VERSION_MAJOR == 1 + static_cast(data_representation); + return static_cast(type::getCdrSerializedSize(*static_cast(data))) + + 4u /*encapsulation*/; +#else + try + { + eprosima::fastcdr::CdrSizeCalculator calculator( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 :eprosima::fastcdr::CdrVersion::XCDRv2); + size_t current_alignment {0}; + return static_cast(calculator.calculate_serialized_size( + *static_cast(data), current_alignment)) + + 4u /*encapsulation*/; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return 0; + } +#endif // FASTCDR_VERSION_MAJOR == 1 + }; +} + +void* DeliveryMechanismsPubSubType::createData() +{ + return reinterpret_cast(new DeliveryMechanisms()); +} + +void DeliveryMechanismsPubSubType::deleteData( + void* data) +{ + delete(reinterpret_cast(data)); +} + +bool DeliveryMechanismsPubSubType::getKey( + const void* const data, + InstanceHandle_t* handle, + bool force_md5) +{ + if (!m_isGetKeyDefined) + { + return false; + } + + const DeliveryMechanisms* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(m_keyBuffer), + DeliveryMechanisms_max_key_cdr_typesize); + + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::BIG_ENDIANNESS, eprosima::fastcdr::CdrVersion::XCDRv1); +#if FASTCDR_VERSION_MAJOR == 1 + p_type->serializeKey(ser); +#else + eprosima::fastcdr::serialize_key(ser, *p_type); +#endif // FASTCDR_VERSION_MAJOR == 1 + if (force_md5 || DeliveryMechanisms_max_key_cdr_typesize > 16) + { + m_md5.init(); +#if FASTCDR_VERSION_MAJOR == 1 + m_md5.update(m_keyBuffer, static_cast(ser.getSerializedDataLength())); +#else + m_md5.update(m_keyBuffer, static_cast(ser.get_serialized_data_length())); +#endif // FASTCDR_VERSION_MAJOR == 1 + m_md5.finalize(); + for (uint8_t i = 0; i < 16; ++i) + { + handle->value[i] = m_md5.digest[i]; + } + } + else + { + for (uint8_t i = 0; i < 16; ++i) + { + handle->value[i] = m_keyBuffer[i]; + } + } + return true; +} + +void DeliveryMechanismsPubSubType::register_type_object_representation() +{ + register_DeliveryMechanisms_type_identifier(type_identifiers_); +} + + +// Include auxiliary functions like for serializing/deserializing. +#include "DeliveryMechanismsCdrAux.ipp" diff --git a/examples/cpp/delivery_mechanisms/DeliveryMechanismsPubSubTypes.hpp b/examples/cpp/delivery_mechanisms/DeliveryMechanismsPubSubTypes.hpp new file mode 100644 index 00000000000..6fd9210c569 --- /dev/null +++ b/examples/cpp/delivery_mechanisms/DeliveryMechanismsPubSubTypes.hpp @@ -0,0 +1,188 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 DeliveryMechanismsPubSubTypes.hpp + * This header file contains the declaration of the serialization functions. + * + * This file was generated by the tool fastddsgen. + */ + + +#ifndef FAST_DDS_GENERATED__DELIVERYMECHANISMS_PUBSUBTYPES_HPP +#define FAST_DDS_GENERATED__DELIVERYMECHANISMS_PUBSUBTYPES_HPP + +#include +#include +#include +#include +#include + +#include "DeliveryMechanisms.hpp" + + +#if !defined(GEN_API_VER) || (GEN_API_VER != 2) +#error \ + Generated DeliveryMechanisms is not compatible with current installed Fast DDS. Please, regenerate it with fastddsgen. +#endif // GEN_API_VER + + +#ifndef SWIG +namespace detail { + +template +struct DeliveryMechanisms_rob +{ + friend constexpr typename Tag::type get( + Tag) + { + return M; + } + +}; + +struct DeliveryMechanisms_f +{ + typedef std::array DeliveryMechanisms::* type; + friend constexpr type get( + DeliveryMechanisms_f); +}; + +template struct DeliveryMechanisms_rob; + +template +inline size_t constexpr DeliveryMechanisms_offset_of() +{ + return ((::size_t) &reinterpret_cast((((T*)0)->*get(Tag())))); +} + +} // namespace detail +#endif // ifndef SWIG + + +/*! + * @brief This class represents the TopicDataType of the type DeliveryMechanisms defined by the user in the IDL file. + * @ingroup DeliveryMechanisms + */ +class DeliveryMechanismsPubSubType : public eprosima::fastdds::dds::TopicDataType +{ +public: + + typedef DeliveryMechanisms type; + + eProsima_user_DllExport DeliveryMechanismsPubSubType(); + + eProsima_user_DllExport ~DeliveryMechanismsPubSubType() override; + + eProsima_user_DllExport bool serialize( + const void* const data, + eprosima::fastdds::rtps::SerializedPayload_t* payload) override + { + return serialize(data, payload, eprosima::fastdds::dds::DEFAULT_DATA_REPRESENTATION); + } + + eProsima_user_DllExport bool serialize( + const void* const data, + eprosima::fastdds::rtps::SerializedPayload_t* payload, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool deserialize( + eprosima::fastdds::rtps::SerializedPayload_t* payload, + void* data) override; + + eProsima_user_DllExport std::function getSerializedSizeProvider( + const void* const data) override + { + return getSerializedSizeProvider(data, eprosima::fastdds::dds::DEFAULT_DATA_REPRESENTATION); + } + + eProsima_user_DllExport std::function getSerializedSizeProvider( + const void* const data, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool getKey( + const void* const data, + eprosima::fastdds::rtps::InstanceHandle_t* ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport void* createData() override; + + eProsima_user_DllExport void deleteData( + void* data) override; + + //Register TypeObject representation in Fast DDS TypeObjectRegistry + eProsima_user_DllExport void register_type_object_representation() override; + +#ifdef TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + eProsima_user_DllExport inline bool is_bounded() const override + { + return true; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + +#ifdef TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + eProsima_user_DllExport inline bool is_plain() const override + { + return is_plain_xcdrv1_impl(); + } + + eProsima_user_DllExport inline bool is_plain( + eprosima::fastdds::dds::DataRepresentationId_t data_representation) const override + { + if (data_representation == eprosima::fastdds::dds::DataRepresentationId_t::XCDR2_DATA_REPRESENTATION) + { + return is_plain_xcdrv2_impl(); + } + else + { + return is_plain_xcdrv1_impl(); + } + } + +#endif // TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + +#ifdef TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + eProsima_user_DllExport inline bool construct_sample( + void* memory) const override + { + new (memory) DeliveryMechanisms(); + return true; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + + eprosima::fastdds::MD5 m_md5; + unsigned char* m_keyBuffer; + +private: + + static constexpr bool is_plain_xcdrv1_impl() + { + return 36ULL == + (detail::DeliveryMechanisms_offset_of() + + sizeof(std::array)); + } + + static constexpr bool is_plain_xcdrv2_impl() + { + return 36ULL == + (detail::DeliveryMechanisms_offset_of() + + sizeof(std::array)); + } + +}; + +#endif // FAST_DDS_GENERATED__DELIVERYMECHANISMS_PUBSUBTYPES_HPP + diff --git a/examples/cpp/delivery_mechanisms/DeliveryMechanismsTypeObjectSupport.cxx b/examples/cpp/delivery_mechanisms/DeliveryMechanismsTypeObjectSupport.cxx new file mode 100644 index 00000000000..b5266678e32 --- /dev/null +++ b/examples/cpp/delivery_mechanisms/DeliveryMechanismsTypeObjectSupport.cxx @@ -0,0 +1,171 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 DeliveryMechanismsTypeObjectSupport.cxx + * Source file containing the implementation to register the TypeObject representation of the described types in the IDL file + * + * This file was generated by the tool fastddsgen. + */ + +#include "DeliveryMechanismsTypeObjectSupport.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DeliveryMechanisms.hpp" + + +using namespace eprosima::fastdds::dds::xtypes; + +// TypeIdentifier is returned by reference: dependent structures/unions are registered in this same method +void register_DeliveryMechanisms_type_identifier( + TypeIdentifierPair& type_ids_DeliveryMechanisms) +{ + + ReturnCode_t return_code_DeliveryMechanisms {eprosima::fastdds::dds::RETCODE_OK}; + return_code_DeliveryMechanisms = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "DeliveryMechanisms", type_ids_DeliveryMechanisms); + if (eprosima::fastdds::dds::RETCODE_OK != return_code_DeliveryMechanisms) + { + StructTypeFlag struct_flags_DeliveryMechanisms = TypeObjectUtils::build_struct_type_flag(eprosima::fastdds::dds::xtypes::ExtensibilityKind::FINAL, + false, false); + QualifiedTypeName type_name_DeliveryMechanisms = "DeliveryMechanisms"; + eprosima::fastcdr::optional type_ann_builtin_DeliveryMechanisms; + eprosima::fastcdr::optional ann_custom_DeliveryMechanisms; + AppliedAnnotationSeq tmp_ann_custom_DeliveryMechanisms; + eprosima::fastcdr::optional verbatim_DeliveryMechanisms; + if (!tmp_ann_custom_DeliveryMechanisms.empty()) + { + ann_custom_DeliveryMechanisms = tmp_ann_custom_DeliveryMechanisms; + } + + CompleteTypeDetail detail_DeliveryMechanisms = TypeObjectUtils::build_complete_type_detail(type_ann_builtin_DeliveryMechanisms, ann_custom_DeliveryMechanisms, type_name_DeliveryMechanisms.to_string()); + CompleteStructHeader header_DeliveryMechanisms; + header_DeliveryMechanisms = TypeObjectUtils::build_complete_struct_header(TypeIdentifier(), detail_DeliveryMechanisms); + CompleteStructMemberSeq member_seq_DeliveryMechanisms; + { + TypeIdentifierPair type_ids_index; + ReturnCode_t return_code_index {eprosima::fastdds::dds::RETCODE_OK}; + return_code_index = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "_uint32_t", type_ids_index); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_index) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "index Structure member TypeIdentifier unknown to TypeObjectRegistry."); + return; + } + StructMemberFlag member_flags_index = TypeObjectUtils::build_struct_member_flag(eprosima::fastdds::dds::xtypes::TryConstructFailAction::DISCARD, + false, false, false, false); + MemberId member_id_index = 0x00000000; + bool common_index_ec {false}; + CommonStructMember common_index {TypeObjectUtils::build_common_struct_member(member_id_index, member_flags_index, TypeObjectUtils::retrieve_complete_type_identifier(type_ids_index, common_index_ec))}; + if (!common_index_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Structure index member TypeIdentifier inconsistent."); + return; + } + MemberName name_index = "index"; + eprosima::fastcdr::optional member_ann_builtin_index; + ann_custom_DeliveryMechanisms.reset(); + CompleteMemberDetail detail_index = TypeObjectUtils::build_complete_member_detail(name_index, member_ann_builtin_index, ann_custom_DeliveryMechanisms); + CompleteStructMember member_index = TypeObjectUtils::build_complete_struct_member(common_index, detail_index); + TypeObjectUtils::add_complete_struct_member(member_seq_DeliveryMechanisms, member_index); + } + { + TypeIdentifierPair type_ids_message; + ReturnCode_t return_code_message {eprosima::fastdds::dds::RETCODE_OK}; + return_code_message = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "anonymous_array_char_32", type_ids_message); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_message) + { + return_code_message = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "_char", type_ids_message); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_message) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "Array element TypeIdentifier unknown to TypeObjectRegistry."); + return; + } + bool element_identifier_anonymous_array_char_32_ec {false}; + TypeIdentifier* element_identifier_anonymous_array_char_32 {new TypeIdentifier(TypeObjectUtils::retrieve_complete_type_identifier(type_ids_message, element_identifier_anonymous_array_char_32_ec))}; + if (!element_identifier_anonymous_array_char_32_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Array element TypeIdentifier inconsistent."); + return; + } + EquivalenceKind equiv_kind_anonymous_array_char_32 = EK_COMPLETE; + if (TK_NONE == type_ids_message.type_identifier2()._d()) + { + equiv_kind_anonymous_array_char_32 = EK_BOTH; + } + CollectionElementFlag element_flags_anonymous_array_char_32 = 0; + PlainCollectionHeader header_anonymous_array_char_32 = TypeObjectUtils::build_plain_collection_header(equiv_kind_anonymous_array_char_32, element_flags_anonymous_array_char_32); + { + SBoundSeq array_bound_seq; + TypeObjectUtils::add_array_dimension(array_bound_seq, static_cast(32)); + + PlainArraySElemDefn array_sdefn = TypeObjectUtils::build_plain_array_s_elem_defn(header_anonymous_array_char_32, array_bound_seq, + eprosima::fastcdr::external(element_identifier_anonymous_array_char_32)); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_s_array_type_identifier(array_sdefn, "anonymous_array_char_32", type_ids_message)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "anonymous_array_char_32 already registered in TypeObjectRegistry for a different type."); + } + } + } + StructMemberFlag member_flags_message = TypeObjectUtils::build_struct_member_flag(eprosima::fastdds::dds::xtypes::TryConstructFailAction::DISCARD, + false, false, false, false); + MemberId member_id_message = 0x00000001; + bool common_message_ec {false}; + CommonStructMember common_message {TypeObjectUtils::build_common_struct_member(member_id_message, member_flags_message, TypeObjectUtils::retrieve_complete_type_identifier(type_ids_message, common_message_ec))}; + if (!common_message_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Structure message member TypeIdentifier inconsistent."); + return; + } + MemberName name_message = "message"; + eprosima::fastcdr::optional member_ann_builtin_message; + ann_custom_DeliveryMechanisms.reset(); + CompleteMemberDetail detail_message = TypeObjectUtils::build_complete_member_detail(name_message, member_ann_builtin_message, ann_custom_DeliveryMechanisms); + CompleteStructMember member_message = TypeObjectUtils::build_complete_struct_member(common_message, detail_message); + TypeObjectUtils::add_complete_struct_member(member_seq_DeliveryMechanisms, member_message); + } + CompleteStructType struct_type_DeliveryMechanisms = TypeObjectUtils::build_complete_struct_type(struct_flags_DeliveryMechanisms, header_DeliveryMechanisms, member_seq_DeliveryMechanisms); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_struct_type_object(struct_type_DeliveryMechanisms, type_name_DeliveryMechanisms.to_string(), type_ids_DeliveryMechanisms)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "DeliveryMechanisms already registered in TypeObjectRegistry for a different type."); + } + } +} + diff --git a/examples/cpp/delivery_mechanisms/DeliveryMechanismsTypeObjectSupport.hpp b/examples/cpp/delivery_mechanisms/DeliveryMechanismsTypeObjectSupport.hpp new file mode 100644 index 00000000000..d171f6da944 --- /dev/null +++ b/examples/cpp/delivery_mechanisms/DeliveryMechanismsTypeObjectSupport.hpp @@ -0,0 +1,56 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 DeliveryMechanismsTypeObjectSupport.hpp + * Header file containing the API required to register the TypeObject representation of the described types in the IDL file + * + * This file was generated by the tool fastddsgen. + */ + +#ifndef FAST_DDS_GENERATED__DELIVERYMECHANISMS_TYPE_OBJECT_SUPPORT_HPP +#define FAST_DDS_GENERATED__DELIVERYMECHANISMS_TYPE_OBJECT_SUPPORT_HPP + +#include + + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#define eProsima_user_DllExport __declspec( dllexport ) +#else +#define eProsima_user_DllExport +#endif // EPROSIMA_USER_DLL_EXPORT +#else +#define eProsima_user_DllExport +#endif // _WIN32 + +#ifndef DOXYGEN_SHOULD_SKIP_THIS_PUBLIC + +/** + * @brief Register DeliveryMechanisms related TypeIdentifier. + * Fully-descriptive TypeIdentifiers are directly registered. + * Hash TypeIdentifiers require to fill the TypeObject information and hash it, consequently, the TypeObject is + * indirectly registered as well. + * + * @param[out] TypeIdentifier of the registered type. + * The returned TypeIdentifier corresponds to the complete TypeIdentifier in case of hashed TypeIdentifiers. + * Invalid TypeIdentifier is returned in case of error. + */ +eProsima_user_DllExport void register_DeliveryMechanisms_type_identifier( + eprosima::fastdds::dds::xtypes::TypeIdentifierPair& type_ids); + + +#endif // DOXYGEN_SHOULD_SKIP_THIS_PUBLIC + +#endif // FAST_DDS_GENERATED__DELIVERYMECHANISMS_TYPE_OBJECT_SUPPORT_HPP diff --git a/examples/cpp/delivery_mechanisms/PubSubApp.cpp b/examples/cpp/delivery_mechanisms/PubSubApp.cpp new file mode 100644 index 00000000000..1676078c57b --- /dev/null +++ b/examples/cpp/delivery_mechanisms/PubSubApp.cpp @@ -0,0 +1,418 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 PubSubApp.cpp + * + */ + +#include "PubSubApp.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Application.hpp" +#include "CLIParser.hpp" +#include "DeliveryMechanismsPubSubTypes.hpp" + +using namespace eprosima::fastdds::dds; +using namespace eprosima::fastdds::rtps; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace delivery_mechanisms { + +PubSubApp::PubSubApp( + const CLIParser::delivery_mechanisms_config& config, + const std::string& topic_name) + : participant_(nullptr) + , publisher_(nullptr) + , subscriber_(nullptr) + , topic_(nullptr) + , reader_(nullptr) + , writer_(nullptr) + , type_(new DeliveryMechanismsPubSubType()) + , matched_(0) + , index_of_last_sample_sent_(0) + , received_samples_(0) + , samples_(config.samples) + , stop_(false) +{ + // Check that the generated type fulfils example constraints: it is plain and bounded + if (!type_->is_plain() || !type_->is_bounded()) + { + throw std::runtime_error( + "Example generated type does not fulfil the example constraints: it is not plain and/or bounded"); + } + + // Create the participant + DomainParticipantQos pqos = PARTICIPANT_QOS_DEFAULT; + pqos.name("DeliveryMechanisms_pubsub_participant"); + pqos.transport().use_builtin_transports = false; + + uint32_t max_samples = samples_; + if (max_samples == 0) + { + max_samples = DATAWRITER_QOS_DEFAULT.resource_limits().max_samples_per_instance; + } + + if (config.ignore_local_endpoints) + { + pqos.properties().properties().emplace_back( + "fastdds.ignore_local_endpoints", + "true"); + } + + // Transport default definitions + pqos.transport().use_builtin_transports = false; + LibrarySettings library_settings; + library_settings.intraprocess_delivery = IntraprocessDeliveryType::INTRAPROCESS_OFF; + + switch (config.delivery_mechanism) + { + case CLIParser::DeliveryMechanismKind::INTRA_PROCESS: + { + // No transport needed, but at least a transport needs to be declared to avoid participant creation failure + pqos.transport().use_builtin_transports = true; + library_settings.intraprocess_delivery = IntraprocessDeliveryType::INTRAPROCESS_FULL; + break; + } + case CLIParser::DeliveryMechanismKind::SHM: + case CLIParser::DeliveryMechanismKind::DATA_SHARING: + { + std::shared_ptr shm_transport_ = + std::make_shared(); + shm_transport_->segment_size(shm_transport_->max_message_size() * max_samples); + pqos.transport().user_transports.push_back(shm_transport_); + break; + } + case CLIParser::DeliveryMechanismKind::LARGE_DATA: + { + // Large Data is a builtin transport + pqos.transport().use_builtin_transports = true; + pqos.setup_transports(eprosima::fastdds::rtps::BuiltinTransports::LARGE_DATA); + break; + } + case CLIParser::DeliveryMechanismKind::TCPv4: + { + std::shared_ptr tcp_v4_transport_ = std::make_shared(); + pqos.wire_protocol().builtin.discovery_config.leaseDuration = eprosima::fastdds::c_TimeInfinite; + pqos.wire_protocol().builtin.discovery_config.leaseDuration_announcementperiod = Duration_t(5, 0); + tcp_v4_transport_->sendBufferSize = 0; + tcp_v4_transport_->receiveBufferSize = 0; + std::string tcp_ip_address = "127.0.0.1"; + if (!config.tcp_ip_address.empty()) + { + tcp_ip_address = config.tcp_ip_address; + } + // Set unicast locators + eprosima::fastdds::rtps::Locator_t tcp_v4_locator_; + tcp_v4_locator_.kind = LOCATOR_KIND_TCPv4; + eprosima::fastdds::rtps::IPLocator::setIPv4(tcp_v4_locator_, tcp_ip_address); + eprosima::fastdds::rtps::IPLocator::setPhysicalPort(tcp_v4_locator_, 5100); + pqos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(tcp_v4_locator_); + pqos.wire_protocol().default_unicast_locator_list.push_back(tcp_v4_locator_); + tcp_v4_transport_->set_WAN_address(tcp_ip_address); + tcp_v4_transport_->add_listener_port(5100); + pqos.transport().user_transports.push_back(tcp_v4_transport_); + Locator tcp_v4_initial_peers_locator_; + tcp_v4_initial_peers_locator_.kind = LOCATOR_KIND_TCPv4; + tcp_v4_initial_peers_locator_.port = 5100; + eprosima::fastdds::rtps::IPLocator::setIPv4(tcp_v4_initial_peers_locator_, tcp_ip_address); + pqos.wire_protocol().builtin.initialPeersList.push_back(tcp_v4_initial_peers_locator_); + break; + } + case CLIParser::DeliveryMechanismKind::TCPv6: + { + std::shared_ptr tcp_v6_transport_ = std::make_shared(); + pqos.wire_protocol().builtin.discovery_config.leaseDuration = eprosima::fastdds::c_TimeInfinite; + pqos.wire_protocol().builtin.discovery_config.leaseDuration_announcementperiod = Duration_t(5, 0); + tcp_v6_transport_->sendBufferSize = 0; + tcp_v6_transport_->receiveBufferSize = 0; + std::string tcp_ip_address = "::1"; + if (!config.tcp_ip_address.empty()) + { + tcp_ip_address = config.tcp_ip_address; + } + // Set unicast locators + eprosima::fastdds::rtps::Locator_t tcp_v6_locator_; + tcp_v6_locator_.kind = LOCATOR_KIND_TCPv6; + eprosima::fastdds::rtps::IPLocator::setIPv6(tcp_v6_locator_, tcp_ip_address); + eprosima::fastdds::rtps::IPLocator::setPhysicalPort(tcp_v6_locator_, 5100); + pqos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(tcp_v6_locator_); + pqos.wire_protocol().default_unicast_locator_list.push_back(tcp_v6_locator_); + tcp_v6_transport_->add_listener_port(5100); + pqos.transport().user_transports.push_back(tcp_v6_transport_); + Locator tcp_v6_initial_peers_locator_; + tcp_v6_initial_peers_locator_.kind = LOCATOR_KIND_TCPv6; + tcp_v6_initial_peers_locator_.port = 5100; + eprosima::fastdds::rtps::IPLocator::setIPv6(tcp_v6_initial_peers_locator_, tcp_ip_address); + pqos.wire_protocol().builtin.initialPeersList.push_back(tcp_v6_initial_peers_locator_); + break; + } + case CLIParser::DeliveryMechanismKind::UDPv4: + { + pqos.transport().user_transports.push_back(std::make_shared()); + break; + } + case CLIParser::DeliveryMechanismKind::UDPv6: + { + pqos.transport().user_transports.push_back(std::make_shared()); + break; + } + default: + { + pqos.transport().use_builtin_transports = true; + break; + } + } + + auto factory = DomainParticipantFactory::get_instance(); + factory->set_library_settings(library_settings); + participant_ = factory->create_participant(config.domain, pqos, nullptr, StatusMask::none()); + if (participant_ == nullptr) + { + throw std::runtime_error("Participant initialization failed"); + } + + // Register the type + type_.register_type(participant_); + + // Create the publisher + PublisherQos pub_qos = PUBLISHER_QOS_DEFAULT; + participant_->get_default_publisher_qos(pub_qos); + publisher_ = participant_->create_publisher(pub_qos, nullptr, StatusMask::none()); + if (publisher_ == nullptr) + { + throw std::runtime_error("Publisher initialization failed"); + } + + // Create the subscriber + SubscriberQos sub_qos = SUBSCRIBER_QOS_DEFAULT; + participant_->get_default_subscriber_qos(sub_qos); + subscriber_ = participant_->create_subscriber(sub_qos, nullptr, StatusMask::none()); + if (subscriber_ == nullptr) + { + throw std::runtime_error("Subscriber initialization failed"); + } + + // Create the topic + TopicQos topic_qos = TOPIC_QOS_DEFAULT; + participant_->get_default_topic_qos(topic_qos); + topic_ = participant_->create_topic(topic_name, type_.get_type_name(), topic_qos); + if (topic_ == nullptr) + { + throw std::runtime_error("Topic initialization failed"); + } + + // Create the data reader and data writer + DataReaderQos reader_qos = DATAREADER_QOS_DEFAULT; + DataWriterQos writer_qos = DATAWRITER_QOS_DEFAULT; + subscriber_->get_default_datareader_qos(reader_qos); + publisher_->get_default_datawriter_qos(writer_qos); + reader_qos.reliability().kind = ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS; + writer_qos.reliability().kind = ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS; + reader_qos.durability().kind = DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS; + writer_qos.durability().kind = DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS; + reader_qos.history().kind = HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS; + writer_qos.history().kind = HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS; + reader_qos.history().depth = max_samples; + writer_qos.history().depth = max_samples; + reader_qos.resource_limits().max_samples_per_instance = max_samples; + writer_qos.resource_limits().max_samples_per_instance = max_samples; + reader_qos.resource_limits().max_samples = reader_qos.resource_limits().max_instances * max_samples; + writer_qos.resource_limits().max_samples = writer_qos.resource_limits().max_instances * max_samples; + if (CLIParser::DeliveryMechanismKind::DATA_SHARING == config.delivery_mechanism) + { + reader_qos.data_sharing().automatic(); + writer_qos.data_sharing().automatic(); + } + else + { + reader_qos.data_sharing().off(); + writer_qos.data_sharing().off(); + } + reader_ = subscriber_->create_datareader(topic_, reader_qos, this, StatusMask::all()); + if (reader_ == nullptr) + { + throw std::runtime_error("DataReader initialization failed"); + } + writer_ = publisher_->create_datawriter(topic_, writer_qos, this, StatusMask::all()); + if (writer_ == nullptr) + { + throw std::runtime_error("DataWriter initialization failed"); + } +} + +PubSubApp::~PubSubApp() +{ + if (nullptr != participant_) + { + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); + + // Delete DomainParticipant + DomainParticipantFactory::get_instance()->delete_participant(participant_); + } +} + +void PubSubApp::on_publication_matched( + eprosima::fastdds::dds::DataWriter* /*writer*/, + const PublicationMatchedStatus& info) +{ + if (info.current_count_change == 1) + { + matched_ = info.current_count; + std::cout << "Pub matched." << std::endl; + cv_.notify_one(); + } + else if (info.current_count_change == -1) + { + matched_ = info.current_count; + std::cout << "Pub unmatched." << std::endl; + } + else + { + std::cout << info.current_count_change + << " is not a valid value for PublicationMatchedStatus current count change" << std::endl; + } +} + +void PubSubApp::on_subscription_matched( + DataReader* /*reader*/, + const SubscriptionMatchedStatus& info) +{ + if (info.current_count_change == 1) + { + std::cout << "Sub matched." << std::endl; + } + else if (info.current_count_change == -1) + { + std::cout << "Sub unmatched." << std::endl; + } + else + { + std::cout << info.current_count_change + << " is not a valid value for SubscriptionMatchedStatus current count change" << std::endl; + } +} + +void PubSubApp::on_data_available( + DataReader* reader) +{ + FASTDDS_CONST_SEQUENCE(DataSeq, DeliveryMechanisms); + + DataSeq delivery_mechanisms_sequence; + SampleInfoSeq info_sequence; + while ((!is_stopped()) && ((samples_ == 0) || ((samples_ > 0) && (received_samples_ < samples_))) + && (RETCODE_OK == reader->take(delivery_mechanisms_sequence, info_sequence))) + { + for (LoanableCollection::size_type i = 0; i < info_sequence.length(); ++i) + { + if ((info_sequence[i].instance_state == ALIVE_INSTANCE_STATE) && info_sequence[i].valid_data) + { + const DeliveryMechanisms& delivery_mechanisms_ = delivery_mechanisms_sequence[i]; + + received_samples_++; + std::cout << "Sample: '" << delivery_mechanisms_.message().data() << "' with index: '" << + delivery_mechanisms_.index() << "' RECEIVED" << std::endl; + } + } + reader->return_loan(delivery_mechanisms_sequence, info_sequence); + } +} + +void PubSubApp::run() +{ + while (!is_stopped()) + { + // publisher does not send more samples, but app does not stop + if ((samples_ == 0) || ((samples_ > 0) && (index_of_last_sample_sent_ < samples_))) + { + if (!publish() && !is_stopped()) + { + std::cout << "Error sending sample with index: '" << index_of_last_sample_sent_ << "'" << std::endl; + } + } + + // Wait for period or stop event + std::unique_lock terminate_lock(mutex_); + cv_.wait_for(terminate_lock, std::chrono::milliseconds(period_ms_), [&]() + { + return is_stopped(); + }); + // check wether the app needs to be stopped + if ((samples_ > 0) && (received_samples_ >= samples_) && (index_of_last_sample_sent_ >= samples_)) + { + stop(); + } + } +} + +bool PubSubApp::publish() +{ + bool ret = false; + // Wait for the data endpoints delivery + std::unique_lock matched_lock(mutex_); + cv_.wait(matched_lock, [&]() + { + // at least one has been discovered + return ((matched_ > 0) || is_stopped()); + }); + void* sample_ = nullptr; + if (!is_stopped() && (RETCODE_OK == writer_->loan_sample(sample_))) + { + DeliveryMechanisms* delivery_mechanisms_ = static_cast(sample_); + delivery_mechanisms_->index() = ++index_of_last_sample_sent_; + memcpy(delivery_mechanisms_->message().data(), "Delivery mechanisms", sizeof("Delivery mechanisms")); + ret = writer_->write(sample_); + std::cout << "Sample: '" << delivery_mechanisms_->message().data() << "' with index: '" + << delivery_mechanisms_->index() << "' SENT" << std::endl; + } + return ret; +} + +bool PubSubApp::is_stopped() +{ + return stop_.load(); +} + +void PubSubApp::stop() +{ + stop_.store(true); + cv_.notify_all(); +} + +} // namespace delivery_mechanisms +} // namespace examples +} // namespace fastdds +} // namespace eprosima diff --git a/examples/cpp/delivery_mechanisms/PubSubApp.hpp b/examples/cpp/delivery_mechanisms/PubSubApp.hpp new file mode 100644 index 00000000000..fab60d8be29 --- /dev/null +++ b/examples/cpp/delivery_mechanisms/PubSubApp.hpp @@ -0,0 +1,121 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 PubSubApp.h + * + */ + +#ifndef _FASTDDS_DISCOVERY_MECHANISMS_PUBSUB_APP_HPP_ +#define _FASTDDS_DISCOVERY_MECHANISMS_PUBSUB_APP_HPP_ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Application.hpp" +#include "CLIParser.hpp" +#include "DeliveryMechanismsPubSubTypes.hpp" + +using namespace eprosima::fastdds::dds; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace delivery_mechanisms { + +class PubSubApp : public Application, public DataReaderListener, public DataWriterListener +{ +public: + + PubSubApp( + const CLIParser::delivery_mechanisms_config& config, + const std::string& topic_name); + + ~PubSubApp(); + + //! Subscription callback + void on_data_available( + DataReader* reader) override; + + //! Publisher matched method + void on_publication_matched( + DataWriter* writer, + const PublicationMatchedStatus& info) override; + + //! Subscriber matched method + void on_subscription_matched( + DataReader* reader, + const SubscriptionMatchedStatus& info) override; + + //! Run the subscriber + void run() override; + + //! Trigger the end of execution + void stop() override; + +private: + + //! Return the current state of execution + bool is_stopped(); + + //! Publish a sample + bool publish(); + + DomainParticipant* participant_; + + Publisher* publisher_; + + Subscriber* subscriber_; + + Topic* topic_; + + DataReader* reader_; + + DataWriter* writer_; + + TypeSupport type_; + + std::condition_variable cv_; + + int32_t matched_; + + std::mutex mutex_; + + const uint32_t period_ms_ = 100; // in ms + + uint32_t index_of_last_sample_sent_; + + uint32_t received_samples_; + + uint32_t samples_; + + std::atomic stop_; +}; + +} // namespace delivery_mechanisms +} // namespace examples +} // namespace fastdds +} // namespace eprosima + +#endif /* _FASTDDS_DISCOVERY_MECHANISMS_PUBSUB_APP_HPP_ */ diff --git a/examples/cpp/delivery_mechanisms/PublisherApp.cpp b/examples/cpp/delivery_mechanisms/PublisherApp.cpp new file mode 100644 index 00000000000..b0478c99a9a --- /dev/null +++ b/examples/cpp/delivery_mechanisms/PublisherApp.cpp @@ -0,0 +1,313 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 PublisherApp.cpp + * + */ + +#include "PublisherApp.hpp" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace eprosima::fastdds::dds; +using namespace eprosima::fastdds::rtps; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace delivery_mechanisms { + +PublisherApp::PublisherApp( + const CLIParser::delivery_mechanisms_config& config, + const std::string& topic_name) + : participant_(nullptr) + , publisher_(nullptr) + , topic_(nullptr) + , writer_(nullptr) + , type_(new DeliveryMechanismsPubSubType()) + , matched_(0) + , index_of_last_sample_sent_(0) + , samples_(config.samples) + , stop_(false) +{ + // Check that the generated type fulfils example constraints: it is plain and bounded + if (!type_->is_plain() || !type_->is_bounded()) + { + throw std::runtime_error( + "Example generated type does not fulfil the example constraints: it is not plain and/or bounded"); + } + + // Create the participant + DomainParticipantQos pqos = PARTICIPANT_QOS_DEFAULT; + pqos.name("DeliveryMechanisms_pub_participant"); + + uint32_t max_samples = samples_; + if (max_samples == 0) + { + max_samples = DATAWRITER_QOS_DEFAULT.resource_limits().max_samples_per_instance; + } + + // Transport default definitions + pqos.transport().use_builtin_transports = false; + LibrarySettings library_settings; + library_settings.intraprocess_delivery = IntraprocessDeliveryType::INTRAPROCESS_OFF; + + switch (config.delivery_mechanism) + { + case CLIParser::DeliveryMechanismKind::INTRA_PROCESS: // (It should never reach this section + { + // No transport needed, but at least a transport needs to be declared to avoid participant creation failure + pqos.transport().use_builtin_transports = true; + library_settings.intraprocess_delivery = IntraprocessDeliveryType::INTRAPROCESS_FULL; + break; + } + case CLIParser::DeliveryMechanismKind::SHM: + case CLIParser::DeliveryMechanismKind::DATA_SHARING: + { + std::shared_ptr shm_transport_ = + std::make_shared(); + shm_transport_->segment_size(shm_transport_->max_message_size() * max_samples); + pqos.transport().user_transports.push_back(shm_transport_); + break; + } + case CLIParser::DeliveryMechanismKind::LARGE_DATA: + { + // Large Data is a builtin transport + pqos.transport().use_builtin_transports = true; + pqos.setup_transports(eprosima::fastdds::rtps::BuiltinTransports::LARGE_DATA); + break; + } + case CLIParser::DeliveryMechanismKind::TCPv4: + { + std::shared_ptr tcp_v4_transport_ = std::make_shared(); + pqos.wire_protocol().builtin.discovery_config.leaseDuration = eprosima::fastdds::c_TimeInfinite; + pqos.wire_protocol().builtin.discovery_config.leaseDuration_announcementperiod = Duration_t(5, 0); + tcp_v4_transport_->sendBufferSize = 0; + tcp_v4_transport_->receiveBufferSize = 0; + std::string tcp_ip_address = "127.0.0.1"; + if (!config.tcp_ip_address.empty()) + { + tcp_ip_address = config.tcp_ip_address; + } + // Set unicast locators + eprosima::fastdds::rtps::Locator_t tcp_v4_locator_; + tcp_v4_locator_.kind = LOCATOR_KIND_TCPv4; + eprosima::fastdds::rtps::IPLocator::setIPv4(tcp_v4_locator_, tcp_ip_address); + eprosima::fastdds::rtps::IPLocator::setPhysicalPort(tcp_v4_locator_, 5100); + pqos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(tcp_v4_locator_); + pqos.wire_protocol().default_unicast_locator_list.push_back(tcp_v4_locator_); + tcp_v4_transport_->set_WAN_address(tcp_ip_address); + tcp_v4_transport_->add_listener_port(5100); + pqos.transport().user_transports.push_back(tcp_v4_transport_); + break; + } + case CLIParser::DeliveryMechanismKind::TCPv6: + { + std::shared_ptr tcp_v6_transport_ = std::make_shared(); + pqos.wire_protocol().builtin.discovery_config.leaseDuration = eprosima::fastdds::c_TimeInfinite; + pqos.wire_protocol().builtin.discovery_config.leaseDuration_announcementperiod = Duration_t(5, 0); + tcp_v6_transport_->sendBufferSize = 0; + tcp_v6_transport_->receiveBufferSize = 0; + std::string tcp_ip_address = "::1"; + if (!config.tcp_ip_address.empty()) + { + tcp_ip_address = config.tcp_ip_address; + } + // Set unicast locators + eprosima::fastdds::rtps::Locator_t tcp_v6_locator_; + tcp_v6_locator_.kind = LOCATOR_KIND_TCPv6; + eprosima::fastdds::rtps::IPLocator::setIPv6(tcp_v6_locator_, tcp_ip_address); + eprosima::fastdds::rtps::IPLocator::setPhysicalPort(tcp_v6_locator_, 5100); + pqos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(tcp_v6_locator_); + pqos.wire_protocol().default_unicast_locator_list.push_back(tcp_v6_locator_); + tcp_v6_transport_->add_listener_port(5100); + pqos.transport().user_transports.push_back(tcp_v6_transport_); + break; + } + case CLIParser::DeliveryMechanismKind::UDPv4: + { + pqos.transport().user_transports.push_back(std::make_shared()); + break; + } + case CLIParser::DeliveryMechanismKind::UDPv6: + { + pqos.transport().user_transports.push_back(std::make_shared()); + break; + } + default: + { + pqos.transport().use_builtin_transports = true; + break; + } + } + + auto factory = DomainParticipantFactory::get_instance(); + factory->set_library_settings(library_settings); + participant_ = factory->create_participant(config.domain, pqos, nullptr, StatusMask::none()); + if (participant_ == nullptr) + { + throw std::runtime_error("Participant initialization failed"); + } + + // Register the type + type_.register_type(participant_); + + // Create the publisher + PublisherQos pub_qos = PUBLISHER_QOS_DEFAULT; + participant_->get_default_publisher_qos(pub_qos); + publisher_ = participant_->create_publisher(pub_qos, nullptr, StatusMask::none()); + if (publisher_ == nullptr) + { + throw std::runtime_error("Publisher initialization failed"); + } + + // Create the topic + TopicQos topic_qos = TOPIC_QOS_DEFAULT; + participant_->get_default_topic_qos(topic_qos); + topic_ = participant_->create_topic(topic_name, type_.get_type_name(), topic_qos); + if (topic_ == nullptr) + { + throw std::runtime_error("Topic initialization failed"); + } + + // Create the data writer + DataWriterQos writer_qos = DATAWRITER_QOS_DEFAULT; + publisher_->get_default_datawriter_qos(writer_qos); + writer_qos.reliability().kind = ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS; + writer_qos.durability().kind = DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS; + writer_qos.history().kind = HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS; + writer_qos.history().depth = max_samples; + writer_qos.resource_limits().max_samples_per_instance = max_samples; + writer_qos.resource_limits().max_samples = writer_qos.resource_limits().max_instances * max_samples; + if (CLIParser::DeliveryMechanismKind::DATA_SHARING == config.delivery_mechanism) + { + writer_qos.data_sharing().automatic(); + } + else + { + writer_qos.data_sharing().off(); + } + writer_ = publisher_->create_datawriter(topic_, writer_qos, this, StatusMask::all()); + if (writer_ == nullptr) + { + throw std::runtime_error("DataWriter initialization failed"); + } +} + +PublisherApp::~PublisherApp() +{ + if (nullptr != participant_) + { + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); + + // Delete DomainParticipant + DomainParticipantFactory::get_instance()->delete_participant(participant_); + } +} + +void PublisherApp::on_publication_matched( + eprosima::fastdds::dds::DataWriter* /*writer*/, + const PublicationMatchedStatus& info) +{ + if (info.current_count_change == 1) + { + matched_ = info.current_count; + std::cout << "Publisher matched." << std::endl; + cv_.notify_one(); + } + else if (info.current_count_change == -1) + { + matched_ = info.current_count; + std::cout << "Publisher unmatched." << std::endl; + } + else + { + std::cout << info.current_count_change + << " is not a valid value for PublicationMatchedStatus current count change" << std::endl; + } +} + +void PublisherApp::run() +{ + while (!is_stopped() && ((samples_ == 0) || (index_of_last_sample_sent_ < samples_))) + { + if (!publish() && !is_stopped()) + { + std::cout << "Error sending sample with index: '" << index_of_last_sample_sent_ << "'" << std::endl; + } + // Wait for period or stop event + std::unique_lock terminate_lock(mutex_); + cv_.wait_for(terminate_lock, std::chrono::milliseconds(period_ms_), [&]() + { + return is_stopped(); + }); + } +} + +bool PublisherApp::publish() +{ + bool ret = false; + // Wait for the data endpoints delivery + std::unique_lock matched_lock(mutex_); + cv_.wait(matched_lock, [&]() + { + // at least one has been discovered + return ((matched_ > 0) || is_stopped()); + }); + void* sample_ = nullptr; + if (!is_stopped() && (RETCODE_OK == writer_->loan_sample(sample_))) + { + DeliveryMechanisms* delivery_mechanisms_ = static_cast(sample_); + delivery_mechanisms_->index() = ++index_of_last_sample_sent_; + memcpy(delivery_mechanisms_->message().data(), "Delivery mechanisms", sizeof("Delivery mechanisms")); + ret = writer_->write(sample_); + std::cout << "Sample: '" << delivery_mechanisms_->message().data() << "' with index: '" + << delivery_mechanisms_->index() << "' SENT" << std::endl; + } + return ret; +} + +bool PublisherApp::is_stopped() +{ + return stop_.load(); +} + +void PublisherApp::stop() +{ + stop_.store(true); + cv_.notify_one(); +} + +} // namespace delivery_mechanisms +} // namespace examples +} // namespace fastdds +} // namespace eprosima diff --git a/examples/cpp/delivery_mechanisms/PublisherApp.hpp b/examples/cpp/delivery_mechanisms/PublisherApp.hpp new file mode 100644 index 00000000000..729a7012cce --- /dev/null +++ b/examples/cpp/delivery_mechanisms/PublisherApp.hpp @@ -0,0 +1,100 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 PublisherApp.hpp + * + */ + +#ifndef _FASTDDS_DISCOVERY_MECHANISMS_PUBLISHER_APP_HPP_ +#define _FASTDDS_DISCOVERY_MECHANISMS_PUBLISHER_APP_HPP_ + + +#include + +#include +#include +#include + +#include "Application.hpp" +#include "CLIParser.hpp" +#include "DeliveryMechanismsPubSubTypes.hpp" + +using namespace eprosima::fastdds::dds; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace delivery_mechanisms { + +class PublisherApp : public Application, public DataWriterListener +{ +public: + + PublisherApp( + const CLIParser::delivery_mechanisms_config& config, + const std::string& topic_name); + + ~PublisherApp(); + + //! Publisher matched method + void on_publication_matched( + DataWriter* writer, + const PublicationMatchedStatus& info) override; + + //! Run publisher + void run() override; + + //! Trigger the end of execution + void stop() override; + +private: + + //! Return the current state of execution + bool is_stopped(); + + //! Publish a sample + bool publish(); + + DomainParticipant* participant_; + + Publisher* publisher_; + + Topic* topic_; + + DataWriter* writer_; + + TypeSupport type_; + + std::condition_variable cv_; + + int32_t matched_; + + std::mutex mutex_; + + const uint32_t period_ms_ = 100; // in ms + + uint32_t index_of_last_sample_sent_; + + uint16_t samples_; + + std::atomic stop_; +}; + +} // namespace delivery_mechanisms +} // namespace examples +} // namespace fastdds +} // namespace eprosima + +#endif /* _FASTDDS_DISCOVERY_MECHANISMS_PUBLISHER_APP_HPP_ */ diff --git a/examples/cpp/delivery_mechanisms/README.md b/examples/cpp/delivery_mechanisms/README.md new file mode 100644 index 00000000000..2e0932a92da --- /dev/null +++ b/examples/cpp/delivery_mechanisms/README.md @@ -0,0 +1,147 @@ +# Delivery Mechanisms example + +The *eProsima Fast DDS delivery mechanisms* example is an application intended to be a DDS deployment with all the available delivery mechanisms. + +This example is part of the suite of examples designed by eProsima that aims to illustrate the features and possible configurations of DDS deployments through *eProsima Fast DDS*. + +In this case, the *delivery mechanisms* example allows configuring all the possible delivery mechanisms for communicating the example application. + + +* [Description of the example](#description-of-the-example) +* [Run the example](#run-the-example) +* [Ignore local endpoints](#ignore-local-endpoints) + +## Description of the example + +Each example application (publisher, subscriber, and pubsub) creates the required DDS entities per case. +Each application inherits from the corresponding listener(s) class(es), overriding the listener's method associated to each event. +When an event occurs, the callback method is triggered. + +Moreover, this example uses loans API in both reading and writing calls (refer to ``on_data_available()`` and ``publish()`` methods, respectively) + +The delivery mechanisms configuration considers all the possible delivery mechanisms, that can be configured by using **``-m``** or **``--mechanism``** flag, followed by any of these options: + +* **``data-sharing``** option instantiates a shared memory transport, but uses data-sharing delivery to write in the memory segment. +* **``intra-process``** option shares the payload pool between the participant's datareader and datawriter. + This option can only be available when the endpoints belong to the same participant and same process, so it can only be used by the PubSub application. +* **``large-data``** option instantiates a UDPv4 multicast transport to perform PDP discovery phase, and a TCPv4 and SHM transports to perform user data communication. + Fast DDS priors SHM over TCP if possible. +* **``SHM``** option instantiates a shared memory transport. +* **``TCPv4``** option instantiates a TCP for IPv4 transport. +* **``TCPv6``** option instantiates a TCP for IPv6 transport. +* **``UDPv4``** option instantiates a UDP for IPv4 transport. +* **``UDPv6``** option instantiates a UDP for IPv6 transport. + +If it is not configured, the default delivery mechanisms are the default builtin transports: UDPv4 and SHM transports are instantiated, and Fast DDS priors SHM over UDP is possible. + +All the example available arguments can be queried running the executable with the **``-h``** or **``--help``** argument. + +**Note**: This example type have been purposely configured as plain, bounded, and ``FINAL`` extensibility, in order to meet all delivery mechanisms constraints. + +## Run the example + +To launch this example, two different terminals are required. One of them will run the publisher example application, and the other will run the subscriber application. + +### Delivery mechanisms publisher + +* Ubuntu ( / MacOS ) + + ```shell + user@machine:example_path$ ./delivery_mechanisms publisher + Publisher running. Please press Ctrl+C to stop the Publisher at any time. + ``` + +* Windows + + ```powershell + example_path> delivery_mechanisms.exe publisher + Publisher running. Please press Ctrl+C to stop the Publisher at any time. + ``` + +### Delivery mechanisms subscriber + +* Ubuntu ( / MacOS ) + + ```shell + user@machine:example_path$ ./delivery_mechanisms subscriber + Subscriber running. Please press Ctrl+C to stop the Subscriber at any time. + ``` + +* Windows + + ```powershell + example_path> delivery_mechanisms.exe subscriber + Subscriber running. Please press Ctrl+C to stop the Subscriber at any time. + ``` + +### Delivery mechanisms pubsub + +* Ubuntu ( / MacOS ) + + ```shell + user@machine:example_path$ ./delivery_mechanisms pubsub + PubSub running. Please press Ctrl+C to stop the PubSub at any time. + ``` + +* Windows + + ```powershell + example_path> delivery_mechanisms.exe pubsub + PubSub running. Please press Ctrl+C to stop the PubSub at any time. + +## Expected output + +Regardless of which application is run first, since the publisher will not start sending data until a subscriber is discovered, the expected output both for publishers and subscribers is a first displayed message acknowledging the match, followed by the amount of samples sent or received until Ctrl+C is pressed. + +### Delivery mechanisms publisher + +```shell +Publisher running. Please press Ctrl+C to stop the Publisher at any time. +Publisher matched. +Sample: 'Delivery mechanisms' with index: '1' SENT +Sample: 'Delivery mechanisms' with index: '2' SENT +Sample: 'Delivery mechanisms' with index: '3' SENT +... +``` + +### Delivery mechanisms subscriber + +```shell +Subscriber running. Please press Ctrl+C to stop the Subscriber at any time. +Subscriber matched. +Sample: 'Delivery mechanisms' with index: '1' RECEIVED +Sample: 'Delivery mechanisms' with index: '2' RECEIVED +Sample: 'Delivery mechanisms' with index: '3' RECEIVED +... +``` + +### Delivery mechanisms pubsub + +```shell +PubSub running. Please press Ctrl+C to stop the PubSub at any time. +Sub matched. +Pub matched. +Sample: 'Delivery mechanisms' with index: '1' SENT +Sample: 'Delivery mechanisms' with index: '1' RECEIVED +Sample: 'Delivery mechanisms' with index: '2' SENT +Sample: 'Delivery mechanisms' with index: '2' RECEIVED + +... +``` + +When Ctrl+C is pressed to stop one of the applications, the other one will show the unmatched status, displaying an informative message, and it will stop sending / receiving samples. The following is a possible output of the publisher application when stopping the subscriber app. + +```shell +Sample: 'Delivery mechanisms' with index: '8' SENT +Sample: 'Delivery mechanisms' with index: '9' SENT +Sample: 'Delivery mechanisms' with index: '10' SENT +Sample: 'Delivery mechanisms' with index: '11' SENT +Publisher unmatched. +``` + +## Ignore local endpoints + +Using argument **``-i``** or **``--ignore-local-endpoints``** will avoid matching compatible datareaders and datawriters that belong to the same domain participant. + +**Note**: It can only be used with the **``PubSub``** entity, otherwise it has no effect. + diff --git a/examples/cpp/delivery_mechanisms/SubscriberApp.cpp b/examples/cpp/delivery_mechanisms/SubscriberApp.cpp new file mode 100644 index 00000000000..aae3b111a51 --- /dev/null +++ b/examples/cpp/delivery_mechanisms/SubscriberApp.cpp @@ -0,0 +1,296 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 SubscriberApp.cpp + * + */ + +#include "SubscriberApp.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Application.hpp" +#include "CLIParser.hpp" +#include "DeliveryMechanismsPubSubTypes.hpp" + +using namespace eprosima::fastdds::dds; +using namespace eprosima::fastdds::rtps; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace delivery_mechanisms { + +SubscriberApp::SubscriberApp( + const CLIParser::delivery_mechanisms_config& config, + const std::string& topic_name) + : participant_(nullptr) + , subscriber_(nullptr) + , topic_(nullptr) + , reader_(nullptr) + , type_(new DeliveryMechanismsPubSubType()) + , received_samples_(0) + , samples_(config.samples) + , stop_(false) +{ + // Check that the generated type fulfils example constraints: it is plain and bounded + if (!type_->is_plain() || !type_->is_bounded()) + { + throw std::runtime_error( + "Example generated type does not fulfil the example constraints: it is not plain and/or bounded"); + } + + // Create the participant + DomainParticipantQos pqos = PARTICIPANT_QOS_DEFAULT; + pqos.name("DeliveryMechanisms_sub_participant"); + pqos.transport().use_builtin_transports = false; + + uint32_t max_samples = samples_; + if (max_samples == 0) + { + max_samples = DATAREADER_QOS_DEFAULT.resource_limits().max_samples_per_instance; + } + + // Transport default definitions + pqos.transport().use_builtin_transports = false; + LibrarySettings library_settings; + library_settings.intraprocess_delivery = IntraprocessDeliveryType::INTRAPROCESS_OFF; + + switch (config.delivery_mechanism) + { + case CLIParser::DeliveryMechanismKind::INTRA_PROCESS: // (It should never reach this section + { + // No transport needed, but at least a transport needs to be declared to avoid participant creation failure + pqos.transport().use_builtin_transports = true; + library_settings.intraprocess_delivery = IntraprocessDeliveryType::INTRAPROCESS_FULL; + break; + } + case CLIParser::DeliveryMechanismKind::SHM: + case CLIParser::DeliveryMechanismKind::DATA_SHARING: + { + std::shared_ptr shm_transport_ = + std::make_shared(); + shm_transport_->segment_size(shm_transport_->max_message_size() * max_samples); + pqos.transport().user_transports.push_back(shm_transport_); + break; + } + case CLIParser::DeliveryMechanismKind::LARGE_DATA: + { + // Large Data is a builtin transport + pqos.transport().use_builtin_transports = true; + pqos.setup_transports(eprosima::fastdds::rtps::BuiltinTransports::LARGE_DATA); + break; + } + case CLIParser::DeliveryMechanismKind::TCPv4: + { + Locator tcp_v4_initial_peers_locator_; + tcp_v4_initial_peers_locator_.kind = LOCATOR_KIND_TCPv4; + tcp_v4_initial_peers_locator_.port = 5100; + std::string tcp_ip_address = "127.0.0.1"; + if (!config.tcp_ip_address.empty()) + { + tcp_ip_address = config.tcp_ip_address; + } + eprosima::fastdds::rtps::IPLocator::setIPv4(tcp_v4_initial_peers_locator_, tcp_ip_address); + pqos.wire_protocol().builtin.initialPeersList.push_back(tcp_v4_initial_peers_locator_); + pqos.wire_protocol().builtin.discovery_config.leaseDuration = eprosima::fastdds::c_TimeInfinite; + pqos.wire_protocol().builtin.discovery_config.leaseDuration_announcementperiod = Duration_t(5, 0); + pqos.transport().user_transports.push_back(std::make_shared()); + break; + } + case CLIParser::DeliveryMechanismKind::TCPv6: + { + Locator tcp_v6_initial_peers_locator_; + tcp_v6_initial_peers_locator_.kind = LOCATOR_KIND_TCPv6; + tcp_v6_initial_peers_locator_.port = 5100; + std::string tcp_ip_address = "::1"; + if (!config.tcp_ip_address.empty()) + { + tcp_ip_address = config.tcp_ip_address; + } + eprosima::fastdds::rtps::IPLocator::setIPv6(tcp_v6_initial_peers_locator_, tcp_ip_address); + pqos.wire_protocol().builtin.initialPeersList.push_back(tcp_v6_initial_peers_locator_); + pqos.wire_protocol().builtin.discovery_config.leaseDuration = eprosima::fastdds::c_TimeInfinite; + pqos.wire_protocol().builtin.discovery_config.leaseDuration_announcementperiod = Duration_t(5, 0); + pqos.transport().user_transports.push_back(std::make_shared()); + break; + } + case CLIParser::DeliveryMechanismKind::UDPv4: + { + pqos.transport().user_transports.push_back(std::make_shared()); + break; + } + case CLIParser::DeliveryMechanismKind::UDPv6: + { + pqos.transport().user_transports.push_back(std::make_shared()); + break; + } + default: + { + pqos.transport().use_builtin_transports = true; + break; + } + } + + auto factory = DomainParticipantFactory::get_instance(); + factory->set_library_settings(library_settings); + participant_ = factory->create_participant(config.domain, pqos, nullptr, StatusMask::none()); + if (participant_ == nullptr) + { + throw std::runtime_error("Participant initialization failed"); + } + + // Register the type + type_.register_type(participant_); + + // Create the subscriber + SubscriberQos sub_qos = SUBSCRIBER_QOS_DEFAULT; + participant_->get_default_subscriber_qos(sub_qos); + subscriber_ = participant_->create_subscriber(sub_qos, nullptr, StatusMask::none()); + if (subscriber_ == nullptr) + { + throw std::runtime_error("Subscriber initialization failed"); + } + + // Create the topic + TopicQos topic_qos = TOPIC_QOS_DEFAULT; + participant_->get_default_topic_qos(topic_qos); + topic_ = participant_->create_topic(topic_name, type_.get_type_name(), topic_qos); + if (topic_ == nullptr) + { + throw std::runtime_error("Topic initialization failed"); + } + + // Create the data reader + DataReaderQos reader_qos = DATAREADER_QOS_DEFAULT; + subscriber_->get_default_datareader_qos(reader_qos); + reader_qos.reliability().kind = ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS; + reader_qos.durability().kind = DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS; + reader_qos.history().kind = HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS; + reader_qos.history().depth = max_samples; + reader_qos.resource_limits().max_samples_per_instance = max_samples; + reader_qos.resource_limits().max_samples = reader_qos.resource_limits().max_instances * max_samples; + if (CLIParser::DeliveryMechanismKind::DATA_SHARING == config.delivery_mechanism) + { + reader_qos.data_sharing().automatic(); + } + else + { + reader_qos.data_sharing().off(); + } + reader_ = subscriber_->create_datareader(topic_, reader_qos, this, StatusMask::all()); + if (reader_ == nullptr) + { + throw std::runtime_error("DataReader initialization failed"); + } +} + +SubscriberApp::~SubscriberApp() +{ + if (nullptr != participant_) + { + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); + + // Delete DomainParticipant + DomainParticipantFactory::get_instance()->delete_participant(participant_); + } +} + +void SubscriberApp::on_subscription_matched( + DataReader* /*reader*/, + const SubscriptionMatchedStatus& info) +{ + if (info.current_count_change == 1) + { + std::cout << "Subscriber matched." << std::endl; + } + else if (info.current_count_change == -1) + { + std::cout << "Subscriber unmatched." << std::endl; + } + else + { + std::cout << info.current_count_change + << " is not a valid value for SubscriptionMatchedStatus current count change" << std::endl; + } +} + +void SubscriberApp::on_data_available( + DataReader* reader) +{ + FASTDDS_CONST_SEQUENCE(DataSeq, DeliveryMechanisms); + + DataSeq delivery_mechanisms_sequence; + SampleInfoSeq info_sequence; + while ((!is_stopped()) && (RETCODE_OK == reader->take(delivery_mechanisms_sequence, info_sequence))) + { + for (LoanableCollection::size_type i = 0; i < info_sequence.length(); ++i) + { + if ((info_sequence[i].instance_state == ALIVE_INSTANCE_STATE) && info_sequence[i].valid_data) + { + const DeliveryMechanisms& delivery_mechanisms_ = delivery_mechanisms_sequence[i]; + + received_samples_++; + std::cout << "Sample: '" << delivery_mechanisms_.message().data() << "' with index: '" << + delivery_mechanisms_.index() << "' RECEIVED" << std::endl; + if ((samples_ > 0) && (received_samples_ >= samples_)) + { + stop(); + } + } + } + reader->return_loan(delivery_mechanisms_sequence, info_sequence); + } +} + +void SubscriberApp::run() +{ + std::unique_lock lock_(mutex_); + cv_.wait(lock_, [&] + { + return is_stopped(); + }); +} + +bool SubscriberApp::is_stopped() +{ + return stop_.load(); +} + +void SubscriberApp::stop() +{ + stop_.store(true); + cv_.notify_all(); +} + +} // namespace delivery_mechanisms +} // namespace examples +} // namespace fastdds +} // namespace eprosima diff --git a/examples/cpp/delivery_mechanisms/SubscriberApp.hpp b/examples/cpp/delivery_mechanisms/SubscriberApp.hpp new file mode 100644 index 00000000000..fdb3a5c81f1 --- /dev/null +++ b/examples/cpp/delivery_mechanisms/SubscriberApp.hpp @@ -0,0 +1,100 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 SubscriberApp.h + * + */ + +#ifndef _FASTDDS_DISCOVERY_MECHANISMS_SUBSCRIBER_APP_HPP_ +#define _FASTDDS_DISCOVERY_MECHANISMS_SUBSCRIBER_APP_HPP_ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "Application.hpp" +#include "CLIParser.hpp" +#include "DeliveryMechanismsPubSubTypes.hpp" + +using namespace eprosima::fastdds::dds; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace delivery_mechanisms { + +class SubscriberApp : public Application, public DataReaderListener +{ +public: + + SubscriberApp( + const CLIParser::delivery_mechanisms_config& config, + const std::string& topic_name); + + ~SubscriberApp(); + + //! Subscription callback + void on_data_available( + DataReader* reader) override; + + //! Subscriber matched method + void on_subscription_matched( + DataReader* reader, + const SubscriptionMatchedStatus& info) override; + + //! Run the subscriber + void run() override; + + //! Trigger the end of execution + void stop() override; + +private: + + //! Return the current state of execution + bool is_stopped(); + + DomainParticipant* participant_; + + Subscriber* subscriber_; + + Topic* topic_; + + DataReader* reader_; + + TypeSupport type_; + + std::condition_variable cv_; + + std::mutex mutex_; + + uint32_t received_samples_; + + uint32_t samples_; + + std::atomic stop_; +}; + +} // namespace delivery_mechanisms +} // namespace examples +} // namespace fastdds +} // namespace eprosima + +#endif /* _FASTDDS_DISCOVERY_MECHANISMS_SUBSCRIBER_APP_HPP_ */ diff --git a/examples/cpp/delivery_mechanisms/main.cpp b/examples/cpp/delivery_mechanisms/main.cpp new file mode 100644 index 00000000000..bf1f8afc5d4 --- /dev/null +++ b/examples/cpp/delivery_mechanisms/main.cpp @@ -0,0 +1,96 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 main.cpp + * + */ + +#include +#include +#include + +#include +#include + +#include "Application.hpp" +#include "CLIParser.hpp" + +using eprosima::fastdds::dds::Log; + +using namespace eprosima::fastdds::examples::delivery_mechanisms; + +std::function stop_app_handler; +void signal_handler( + int signum) +{ + stop_app_handler(signum); +} + +int main( + int argc, + char** argv) +{ + auto ret = EXIT_SUCCESS; + const std::string topic_name = "delivery_mechanisms_topic"; + CLIParser::delivery_mechanisms_config config = CLIParser::parse_cli_options(argc, argv); + uint16_t samples = config.samples; + std::string app_name = CLIParser::parse_entity_kind(config.entity); + std::shared_ptr app; + + try + { + app = Application::make_app(config, topic_name); + } + catch (const std::runtime_error& e) + { + EPROSIMA_LOG_ERROR(app_name, e.what()); + ret = EXIT_FAILURE; + } + + if (EXIT_FAILURE != ret) + { + std::thread thread(&Application::run, app); + + if (samples == 0) + { + std::cout << app_name << " running. Please press Ctrl+C to stop the " + << app_name << " at any time." << std::endl; + } + else + { + std::cout << app_name << " running for " << samples << " samples. Please press Ctrl+C to stop the " + << app_name << " at any time." << std::endl; + } + + stop_app_handler = [&](int signum) + { + std::cout << "\n" << CLIParser::parse_signal(signum) << " received, stopping " << app_name + << " execution." << std::endl; + app->stop(); + }; + + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); +#ifndef _WIN32 + signal(SIGQUIT, signal_handler); + signal(SIGHUP, signal_handler); +#endif // _WIN32 + + thread.join(); + } + + Log::Reset(); + return ret; +} diff --git a/test/examples/delivery_mechanisms.compose.yml b/test/examples/delivery_mechanisms.compose.yml new file mode 100644 index 00000000000..ecbb6c6497e --- /dev/null +++ b/test/examples/delivery_mechanisms.compose.yml @@ -0,0 +1,61 @@ +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# 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. +version: "3" + +services: + subscriber: + image: @DOCKER_IMAGE_NAME@ + volumes: + - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ + - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + @TINYXML2_LIB_DIR_COMPOSE_VOLUME@ + environment: + # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@@TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH@ + EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/delivery_mechanisms + ISOLATED_SUBSCRIBER_ADDITIONAL_ARGUMENTS: ${ISUB_ARGS} + # avoid ipc host to isolate this subscriber for sharing memory with other containers + network_mode: host + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/delivery_mechanisms@FILE_EXTENSION@ subscriber --samples 10 $${ISOLATED_SUBSCRIBER_ADDITIONAL_ARGUMENTS}" + + publisher-subscriber: + image: @DOCKER_IMAGE_NAME@ + volumes: + - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ + - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + @TINYXML2_LIB_DIR_COMPOSE_VOLUME@ + environment: + # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@@TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH@ + EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/delivery_mechanisms + PUBLISHER_ADDITIONAL_ARGUMENTS: ${PUB_ARGS} + SUBSCRIBER_ADDITIONAL_ARGUMENTS: ${SUB_ARGS} + network_mode: host + ipc: host + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/delivery_mechanisms@FILE_EXTENSION@ publisher --samples 10 $${PUBLISHER_ADDITIONAL_ARGUMENTS} & $${EXAMPLE_DIR}/delivery_mechanisms@FILE_EXTENSION@ subscriber --samples 10 $${SUBSCRIBER_ADDITIONAL_ARGUMENTS}" + + pubsub: + image: @DOCKER_IMAGE_NAME@ + volumes: + - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ + - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + @TINYXML2_LIB_DIR_COMPOSE_VOLUME@ + environment: + # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@@TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH@ + EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/delivery_mechanisms + PUBSUB_ADDITIONAL_ARGUMENTS: ${PUBSUB_ARGS} + network_mode: host + ipc: host + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/delivery_mechanisms@FILE_EXTENSION@ pubsub --samples 10 $${PUBSUB_ADDITIONAL_ARGUMENTS}" diff --git a/test/examples/delivery_mechanisms_isolated.compose.yml b/test/examples/delivery_mechanisms_isolated.compose.yml new file mode 100644 index 00000000000..124e3231edf --- /dev/null +++ b/test/examples/delivery_mechanisms_isolated.compose.yml @@ -0,0 +1,76 @@ +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# 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. +version: "3" + +services: + subscriber: + image: @DOCKER_IMAGE_NAME@ + volumes: + - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ + - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + @TINYXML2_LIB_DIR_COMPOSE_VOLUME@ + environment: + # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@@TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH@ + EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/delivery_mechanisms + ISOLATED_SUBSCRIBER_ADDITIONAL_ARGUMENTS: ${ISUB_ARGS} + # avoid network and ipc host to isolate this subscriber for sharing memory with other containers + networks: + delivery_mechanisms_net: + ipv4_address: 113.1.1.2 + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/delivery_mechanisms@FILE_EXTENSION@ subscriber --samples 10 $${ISOLATED_SUBSCRIBER_ADDITIONAL_ARGUMENTS}" + + publisher-subscriber: + image: @DOCKER_IMAGE_NAME@ + volumes: + - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ + - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + @TINYXML2_LIB_DIR_COMPOSE_VOLUME@ + environment: + # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@@TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH@ + EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/delivery_mechanisms + PUBLISHER_ADDITIONAL_ARGUMENTS: ${PUB_ARGS} + SUBSCRIBER_ADDITIONAL_ARGUMENTS: ${SUB_ARGS} + # avoid network and ipc host to isolate this subscriber for sharing memory with other containers + networks: + delivery_mechanisms_net: + ipv4_address: 113.1.1.3 + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/delivery_mechanisms@FILE_EXTENSION@ subscriber --samples 10 $${SUBSCRIBER_ADDITIONAL_ARGUMENTS} & $${EXAMPLE_DIR}/delivery_mechanisms@FILE_EXTENSION@ publisher --samples 10 $${PUBLISHER_ADDITIONAL_ARGUMENTS}" + + pubsub: + image: @DOCKER_IMAGE_NAME@ + volumes: + - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ + - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + @TINYXML2_LIB_DIR_COMPOSE_VOLUME@ + environment: + # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@@TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH@ + EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/delivery_mechanisms + PUBSUB_ADDITIONAL_ARGUMENTS: ${PUBSUB_ARGS} + # avoid network and ipc host to isolate this subscriber for sharing memory with other containers + networks: + delivery_mechanisms_net: + ipv4_address: 113.1.1.4 + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/delivery_mechanisms@FILE_EXTENSION@ pubsub --samples 10 $${PUBSUB_ADDITIONAL_ARGUMENTS}" + +networks: + delivery_mechanisms_net: + driver: bridge + ipam: + driver: default + config: + - subnet: 113.1.1.0/24 + gateway: 113.1.1.1 diff --git a/test/examples/test_configuration.py b/test/examples/test_configuration.py index 30dc10de7bd..69d740801eb 100644 --- a/test/examples/test_configuration.py +++ b/test/examples/test_configuration.py @@ -60,7 +60,7 @@ def test_configuration(pub_args, sub_args): out = subprocess.check_output(command_prerequisites + '@DOCKER_EXECUTABLE@ compose -f configuration.compose.yml up', stderr=subprocess.STDOUT, shell=True, - timeout=40 + timeout=20 ) render_out = out.decode().split('\n') @@ -141,6 +141,7 @@ def test_configuration_expected_output(pub_args, sub_args, expected_message, n_m """.""" ret = False out = '' + render_out = '' pub_requirements = '--reliable --transient-local --keep-last 10' sub_requirements = '--reliable --transient-local --keep-last 10' @@ -149,7 +150,7 @@ def test_configuration_expected_output(pub_args, sub_args, expected_message, n_m out = subprocess.check_output(command_prerequisites + '@DOCKER_EXECUTABLE@ compose -f configuration.compose.yml up', stderr=subprocess.STDOUT, shell=True, - timeout=30 + timeout=20 ) render_out = out.decode().split('\n') diff --git a/test/examples/test_delivery_mechanisms.py b/test/examples/test_delivery_mechanisms.py new file mode 100644 index 00000000000..84be57bcd3f --- /dev/null +++ b/test/examples/test_delivery_mechanisms.py @@ -0,0 +1,159 @@ +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# 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. + +import subprocess +import pytest + +delivery_test_cases = [ + # Default builtin transports (remove isolated subscriber to avoid flakiness) + ('', '-s 20', '--unknown-argument', '', 30), + ('', '-s 20', '--unknown-argument', '--ignore-local-endpoints', 30), + # Data-sharing isolated subscriber tested in timeout test cases + ('--mechanism data-sharing', '-s 20 --mechanism data-sharing', '--unknown-argument', '--mechanism data-sharing', 30), + ('--mechanism data-sharing', '-s 20 --mechanism data-sharing', '--unknown-argument', '--mechanism data-sharing --ignore-local-endpoints', 30), + # Intra-process only makes sense for pubsub entities. This test forces entities != pubsub to fail, so + # only 1 message is expected per sample (the local one) + ('--unknown-argument', '--unknown-argument', '--unknown-argument', '--mechanism intra-process', 10), + # Large-data (using shared memory, so isolated subscriber is removed to avoid flakiness) + ('--mechanism large-data', '-s 20 --mechanism large-data', '--unknown-argument', '--mechanism large-data', 30), + ('--mechanism large-data', '-s 20 --mechanism large-data', '--unknown-argument', '--mechanism large-data --ignore-local-endpoints', 30), + # Shared memory isolated subscriber tested in timeout test cases + ('--mechanism shm', '-s 20 --mechanism shm', '--unknown-argument', '--mechanism shm', 30), + ('--mechanism shm', '-s 20 --mechanism shm', '--unknown-argument', '--mechanism shm --ignore-local-endpoints', 30), + # TCP takes longer to match, so explicitly expect much more samples in this case. + # TCP is configured through initial peers (a single locator), so we test only one publisher at a time + # Note: pubsub with TCP and ignore-local-endpoints NOT set is not supported, tested in expected output test cases + ('-s 100 --mechanism tcpv4', '-s 100 --mechanism tcpv4', '-s 100 --mechanism tcpv4', '--unknown-command', 200), + ('-s 100 --mechanism tcpv6', '-s 100 --mechanism tcpv6', '-s 100 --mechanism tcpv6', '--unknown-command', 200), + # UDP + ('--mechanism udpv4', '-s 20 --mechanism udpv4', '-s 20 --mechanism udpv4', '--mechanism udpv4', 50), + ('--mechanism udpv4', '-s 20 --mechanism udpv4', '-s 20 --mechanism udpv4', '--mechanism udpv4 --ignore-local-endpoints', 50), + ('--mechanism udpv6', '-s 20 --mechanism udpv6', '-s 20 --mechanism udpv6', '--mechanism udpv6', 50), + ('--mechanism udpv6', '-s 20 --mechanism udpv6', '-s 20 --mechanism udpv6', '--mechanism udpv6 --ignore-local-endpoints', 50) +] + +@pytest.mark.parametrize("pub_args, sub_args, isub_args, pubsub_args, repetitions", delivery_test_cases) +def test_delivery_mechanisms(pub_args, sub_args, isub_args, pubsub_args, repetitions): + """.""" + ret = False + out = '' + + command_prerequisites = 'PUB_ARGS="' + pub_args + '" SUB_ARGS="' + sub_args + '" ISUB_ARGS="' + isub_args + '" PUBSUB_ARGS="' + pubsub_args + '" ' + try: + out = subprocess.check_output(command_prerequisites + '@DOCKER_EXECUTABLE@ compose -f delivery_mechanisms.compose.yml up', + stderr=subprocess.STDOUT, + shell=True, + timeout=30 + ).decode().split('\n') + + sent = 0 + received = 0 + for line in out: + if 'SENT' in line: + sent += 1 + continue + + if 'RECEIVED' in line: + received += 1 + continue + if sent != 0 and received != 0 and repetitions == received: + ret = True + else: + print('ERROR: sent: ' + str(sent) + ', but received: ' + str(received) + + ' (expected: ' + str(repetitions) + ')') + raise subprocess.CalledProcessError(1, '') + + except subprocess.CalledProcessError: + for l in out: + print(l) + except subprocess.TimeoutExpired: + print('TIMEOUT') + print(out) + + assert(ret) + +timeout_test_cases = [ + # Shared memory and data-sharing isolated subscriber timeout test cases + ('--mechanism shm', '--unknown-argument', '--mechanism shm', '--unknown-argument'), + ('--mechanism data-sharing', '--unknown-argument', '--mechanism data-sharing', '--unknown-argument'), + # Incompatible mechanisms timeout test cases + ('--mechanism tcpv4', '--mechanism udpv4', '--mechanism udpv6', '--mechanism tcpv6 -i'), + ('--mechanism shm', '--mechanism data-sharing', '--mechanism large-data', '--mechanism intra-process -i') +] + +@pytest.mark.parametrize("pub_args, sub_args, isub_args, pubsub_args", timeout_test_cases) +def test_delivery_mechanisms_timeout(pub_args, sub_args, isub_args, pubsub_args): + """.""" + ret = False + out = '' + + command_prerequisites = 'PUB_ARGS="' + pub_args + '" SUB_ARGS="' + sub_args + '" ISUB_ARGS="' + isub_args + '" PUBSUB_ARGS="' + pubsub_args + '" ' + try: + out = subprocess.check_output(command_prerequisites + '@DOCKER_EXECUTABLE@ compose -f delivery_mechanisms.compose.yml up', + stderr=subprocess.STDOUT, + shell=True, + timeout=10 + ) + except subprocess.CalledProcessError as e: + print (e.output) + except subprocess.TimeoutExpired: + ret = True + subprocess.check_output('@DOCKER_EXECUTABLE@ compose -f delivery_mechanisms.compose.yml down', + stderr=subprocess.STDOUT, + shell=True, + timeout=15 + ) + + assert(ret) + +# Unsupported delivery mechanisms corner case test +expected_output_test_cases = [ + ('--unknown-argument', '--unknown-argument', '--mechanism tcp', 'Unsupported', 1) +] + +@pytest.mark.parametrize("pub_args, sub_args, pubsub_args, expected_message, n_messages", expected_output_test_cases) +def test_delivery_mechanisms_expected_output(pub_args, sub_args, pubsub_args, expected_message, n_messages): + """.""" + ret = False + out = '' + render_out = '' + + command_prerequisites = 'PUB_ARGS="' + pub_args + '" SUB_ARGS="' + sub_args + '" ISUB_ARGS="' + sub_args + '" PUBSUB_ARGS="' + pubsub_args + '" ' + try: + out = subprocess.check_output(command_prerequisites + '@DOCKER_EXECUTABLE@ compose -f delivery_mechanisms.compose.yml up', + stderr=subprocess.STDOUT, + shell=True, + timeout=20 + ) + render_out = out.decode().split('\n') + + count = 0 + for line in render_out: + if expected_message in line: + count += 1 + continue + + if count >= int(n_messages): + ret = True + else: + print ('ERROR: expected at least: ' + n_messages +' "' + expected_message + '" messages, but received ' + str(count)) + raise subprocess.CalledProcessError(1, render_out) + + except subprocess.CalledProcessError as e: + print (render_out) + except subprocess.TimeoutExpired: + print('TIMEOUT') + print(out) + + assert(ret) diff --git a/test/examples/test_delivery_mechanisms_isolated.py b/test/examples/test_delivery_mechanisms_isolated.py new file mode 100644 index 00000000000..366f8b77ced --- /dev/null +++ b/test/examples/test_delivery_mechanisms_isolated.py @@ -0,0 +1,146 @@ +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# 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. + +import subprocess +import pytest + +isolated_delivery_test_cases = [ + # Default builtin transports (UDP forced) + ('', '-s 20', '-s 20', '', 50), + ('', '-s 20', '-s 20', '--ignore-local-endpoints', 50), + # Large-data with only one publisher (testing TCP) + ('--mechanism large-data', '--unknown-argument', '--mechanism large-data', '--unknown-argument', 10), + # TCP takes longer to match, so explicitly expect much more samples in this case. + # TCP is configured through initial peers (a single locator), so we test only one publisher at a time + # Note: pubsub with TCP and ignore-local-endpoints NOT set is not supported, tested in expected output test cases + ('-s 100 --mechanism tcpv4 -a 113.1.1.3', '-s 100 --mechanism tcpv4 -a 113.1.1.3', '-s 100 --mechanism tcpv4 -a 113.1.1.3', '--unknown-command', 200), + # UDP + ('--mechanism udpv4', '-s 20 --mechanism udpv4', '-s 20 --mechanism udpv4', '--mechanism udpv4', 50), + ('--mechanism udpv4', '-s 20 --mechanism udpv4', '-s 20 --mechanism udpv4', '--mechanism udpv4 --ignore-local-endpoints', 50), +] + +@pytest.mark.parametrize("pub_args, sub_args, isub_args, pubsub_args, repetitions", isolated_delivery_test_cases) +def test_delivery_mechanisms_isolated(pub_args, sub_args, isub_args, pubsub_args, repetitions): + """.""" + ret = False + out = '' + + command_prerequisites = 'PUB_ARGS="' + pub_args + '" SUB_ARGS="' + sub_args + '" ISUB_ARGS="' + isub_args + '" PUBSUB_ARGS="' + pubsub_args + '" ' + try: + out = subprocess.check_output(command_prerequisites + '/usr/bin/docker compose -f delivery_mechanisms_isolated.compose.yml up', + stderr=subprocess.STDOUT, + shell=True, + timeout=30 + ).decode().split('\n') + + sent = 0 + received = 0 + for line in out: + if 'SENT' in line: + sent += 1 + continue + + if 'RECEIVED' in line: + received += 1 + continue + if sent != 0 and received != 0 and repetitions == received: + ret = True + else: + print('ERROR: sent: ' + str(sent) + ', but received: ' + str(received) + + ' (expected: ' + str(repetitions) + ')') + raise subprocess.CalledProcessError(1, '') + + except subprocess.CalledProcessError: + for l in out: + print(l) + except subprocess.TimeoutExpired: + print('TIMEOUT') + print(out) + + assert(ret) + +isolated_timeout_test_cases = [ + # Shared memory and data-sharing isolated subscriber timeout test cases + ('--mechanism shm', '--unknown-command', '--mechanism shm', '--mechanism shm -i'), + ('--mechanism data-sharing', '--unknown-command', '--mechanism data-sharing', '--mechanism data-sharing -i'), + # Incompatible mechanisms timeout test cases + ('--mechanism tcpv4', '--mechanism udpv4', '--mechanism udpv6', '--mechanism tcpv6 -i'), + ('--mechanism shm', '--mechanism data-sharing', '--mechanism large-data', '--mechanism intra-process -i') +] + +@pytest.mark.parametrize("pub_args, sub_args, isub_args, pubsub_args", isolated_timeout_test_cases) +def test_delivery_mechanisms_isolated_timeout(pub_args, sub_args, isub_args, pubsub_args): + """.""" + ret = False + out = '' + + command_prerequisites = 'PUB_ARGS="' + pub_args + '" SUB_ARGS="' + sub_args + '" ISUB_ARGS="' + isub_args + '" PUBSUB_ARGS="' + pubsub_args + '" ' + try: + out = subprocess.check_output(command_prerequisites + '/usr/bin/docker compose -f delivery_mechanisms_isolated.compose.yml up', + stderr=subprocess.STDOUT, + shell=True, + timeout=10 + ) + except subprocess.CalledProcessError as e: + print (e.output) + except subprocess.TimeoutExpired: + ret = True + subprocess.check_output('/usr/bin/docker compose -f delivery_mechanisms_isolated.compose.yml down', + stderr=subprocess.STDOUT, + shell=True, + timeout=15 + ) + + assert(ret) + +# Unsupported delivery mechanisms corner case test +isolated_expected_output_test_cases = [ + ('--unknown-argument', '--unknown-argument', '--mechanism tcp', 'Unsupported', 1) +] + +@pytest.mark.parametrize("pub_args, sub_args, pubsub_args, expected_message, n_messages", isolated_expected_output_test_cases) +def test_delivery_mechanisms_isolated_expected_output(pub_args, sub_args, pubsub_args, expected_message, n_messages): + """.""" + ret = False + out = '' + render_out = '' + + command_prerequisites = 'PUB_ARGS="' + pub_args + '" SUB_ARGS="' + sub_args + '" ISUB_ARGS="' + sub_args + '" PUBSUB_ARGS="' + pubsub_args + '" ' + try: + out = subprocess.check_output(command_prerequisites + '/usr/bin/docker compose -f delivery_mechanisms_isolated.compose.yml up', + stderr=subprocess.STDOUT, + shell=True, + timeout=20 + ) + render_out = out.decode().split('\n') + + count = 0 + for line in render_out: + if expected_message in line: + count += 1 + continue + + if count >= int(n_messages): + ret = True + else: + print ('ERROR: expected at least: ' + n_messages +' "' + expected_message + '" messages, but received ' + str(count)) + raise subprocess.CalledProcessError(1, render_out) + + except subprocess.CalledProcessError as e: + print (render_out) + except subprocess.TimeoutExpired: + print('TIMEOUT') + print(out) + + assert(ret) diff --git a/test/examples/test_hello_world.py b/test/examples/test_hello_world.py index 73fbbaa9568..69b6c278dec 100644 --- a/test/examples/test_hello_world.py +++ b/test/examples/test_hello_world.py @@ -23,7 +23,7 @@ def test_hello_world(): '@DOCKER_EXECUTABLE@ compose -f hello_world.compose.yml up', stderr=subprocess.STDOUT, shell=True, - timeout=30 + timeout=20 ).decode().split('\n') sent = 0 diff --git a/versions.md b/versions.md index 58e31d922be..e9d3f86a282 100644 --- a/versions.md +++ b/versions.md @@ -45,6 +45,7 @@ Forthcoming * Custom payload pool example that uses a user-defined payload pool instead of the default * X-Types example with dynamic type discovery and Hello world example compatibility. * Custom Content filter example + * Delivery mechanisms example with SHM, UDP, TCP, data-sharing and intra-process mechanisms. * Removed `TypeConsistencyQos` from DataReader, and included `TypeConsistencyEnforcementQosPolicy` and `DataRepresentationQosPolicy` * Added new `flow_controller_descriptor_list` XML configuration, remove `ThroughtputController`. * Migrate `#define`s within `BuiltinEndpoints.hpp` to namespaced `constexpr` variables.